1*10187SKrishna.Elango@Sun.COM /* 2*10187SKrishna.Elango@Sun.COM * CDDL HEADER START 3*10187SKrishna.Elango@Sun.COM * 4*10187SKrishna.Elango@Sun.COM * The contents of this file are subject to the terms of the 5*10187SKrishna.Elango@Sun.COM * Common Development and Distribution License (the "License"). 6*10187SKrishna.Elango@Sun.COM * You may not use this file except in compliance with the License. 7*10187SKrishna.Elango@Sun.COM * 8*10187SKrishna.Elango@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10187SKrishna.Elango@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10187SKrishna.Elango@Sun.COM * See the License for the specific language governing permissions 11*10187SKrishna.Elango@Sun.COM * and limitations under the License. 12*10187SKrishna.Elango@Sun.COM * 13*10187SKrishna.Elango@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10187SKrishna.Elango@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10187SKrishna.Elango@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10187SKrishna.Elango@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10187SKrishna.Elango@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10187SKrishna.Elango@Sun.COM * 19*10187SKrishna.Elango@Sun.COM * CDDL HEADER END 20*10187SKrishna.Elango@Sun.COM */ 21*10187SKrishna.Elango@Sun.COM /* 22*10187SKrishna.Elango@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*10187SKrishna.Elango@Sun.COM * Use is subject to license terms. 24*10187SKrishna.Elango@Sun.COM */ 25*10187SKrishna.Elango@Sun.COM 26*10187SKrishna.Elango@Sun.COM /* 27*10187SKrishna.Elango@Sun.COM * Common x86 and SPARC PCI-E to PCI bus bridge nexus driver 28*10187SKrishna.Elango@Sun.COM */ 29*10187SKrishna.Elango@Sun.COM 30*10187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h> 31*10187SKrishna.Elango@Sun.COM #include <sys/conf.h> 32*10187SKrishna.Elango@Sun.COM #include <sys/kmem.h> 33*10187SKrishna.Elango@Sun.COM #include <sys/debug.h> 34*10187SKrishna.Elango@Sun.COM #include <sys/modctl.h> 35*10187SKrishna.Elango@Sun.COM #include <sys/autoconf.h> 36*10187SKrishna.Elango@Sun.COM #include <sys/ddi_impldefs.h> 37*10187SKrishna.Elango@Sun.COM #include <sys/pci.h> 38*10187SKrishna.Elango@Sun.COM #include <sys/ddi.h> 39*10187SKrishna.Elango@Sun.COM #include <sys/sunddi.h> 40*10187SKrishna.Elango@Sun.COM #include <sys/sunndi.h> 41*10187SKrishna.Elango@Sun.COM #include <sys/fm/util.h> 42*10187SKrishna.Elango@Sun.COM #include <sys/pcie.h> 43*10187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h> 44*10187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h> 45*10187SKrishna.Elango@Sun.COM #include <sys/hotplug/pci/pcihp.h> 46*10187SKrishna.Elango@Sun.COM #include <sys/hotplug/pci/pciehpc.h> 47*10187SKrishna.Elango@Sun.COM #include <sys/hotplug/pci/pcishpc.h> 48*10187SKrishna.Elango@Sun.COM #include <sys/open.h> 49*10187SKrishna.Elango@Sun.COM #include <sys/stat.h> 50*10187SKrishna.Elango@Sun.COM #include <sys/file.h> 51*10187SKrishna.Elango@Sun.COM #include <sys/promif.h> /* prom_printf */ 52*10187SKrishna.Elango@Sun.COM #include <sys/disp.h> 53*10187SKrishna.Elango@Sun.COM #include <sys/pcie_pwr.h> 54*10187SKrishna.Elango@Sun.COM #include "pcieb.h" 55*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX 56*10187SKrishna.Elango@Sun.COM #include <io/pciex/pcieb_plx.h> 57*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 58*10187SKrishna.Elango@Sun.COM 59*10187SKrishna.Elango@Sun.COM /*LINTLIBRARY*/ 60*10187SKrishna.Elango@Sun.COM 61*10187SKrishna.Elango@Sun.COM /* panic flag */ 62*10187SKrishna.Elango@Sun.COM int pcieb_die = PF_ERR_FATAL_FLAGS; 63*10187SKrishna.Elango@Sun.COM 64*10187SKrishna.Elango@Sun.COM /* flag to turn on MSI support */ 65*10187SKrishna.Elango@Sun.COM int pcieb_enable_msi = 1; 66*10187SKrishna.Elango@Sun.COM 67*10187SKrishna.Elango@Sun.COM #if defined(DEBUG) 68*10187SKrishna.Elango@Sun.COM uint_t pcieb_dbg_print = 0; 69*10187SKrishna.Elango@Sun.COM 70*10187SKrishna.Elango@Sun.COM static char *pcieb_debug_sym [] = { /* same sequence as pcieb_debug_bit */ 71*10187SKrishna.Elango@Sun.COM /* 0 */ "attach", 72*10187SKrishna.Elango@Sun.COM /* 1 */ "pwr", 73*10187SKrishna.Elango@Sun.COM /* 2 */ "intr" 74*10187SKrishna.Elango@Sun.COM }; 75*10187SKrishna.Elango@Sun.COM #endif /* DEBUG */ 76*10187SKrishna.Elango@Sun.COM 77*10187SKrishna.Elango@Sun.COM static int pcieb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, off_t, 78*10187SKrishna.Elango@Sun.COM off_t, caddr_t *); 79*10187SKrishna.Elango@Sun.COM static int pcieb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, 80*10187SKrishna.Elango@Sun.COM void *); 81*10187SKrishna.Elango@Sun.COM static int pcieb_fm_init(pcieb_devstate_t *pcieb_p); 82*10187SKrishna.Elango@Sun.COM static void pcieb_fm_fini(pcieb_devstate_t *pcieb_p); 83*10187SKrishna.Elango@Sun.COM static int pcieb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap, 84*10187SKrishna.Elango@Sun.COM ddi_iblock_cookie_t *ibc_p); 85*10187SKrishna.Elango@Sun.COM static int pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 86*10187SKrishna.Elango@Sun.COM ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg, 87*10187SKrishna.Elango@Sun.COM ddi_dma_handle_t *handlep); 88*10187SKrishna.Elango@Sun.COM static int pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 89*10187SKrishna.Elango@Sun.COM ddi_dma_handle_t handle, enum ddi_dma_ctlops cmd, off_t *offp, 90*10187SKrishna.Elango@Sun.COM size_t *lenp, caddr_t *objp, uint_t cache_flags); 91*10187SKrishna.Elango@Sun.COM static int pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip, 92*10187SKrishna.Elango@Sun.COM ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 93*10187SKrishna.Elango@Sun.COM 94*10187SKrishna.Elango@Sun.COM static struct bus_ops pcieb_bus_ops = { 95*10187SKrishna.Elango@Sun.COM BUSO_REV, 96*10187SKrishna.Elango@Sun.COM pcieb_bus_map, 97*10187SKrishna.Elango@Sun.COM 0, 98*10187SKrishna.Elango@Sun.COM 0, 99*10187SKrishna.Elango@Sun.COM 0, 100*10187SKrishna.Elango@Sun.COM i_ddi_map_fault, 101*10187SKrishna.Elango@Sun.COM ddi_dma_map, 102*10187SKrishna.Elango@Sun.COM pcieb_dma_allochdl, 103*10187SKrishna.Elango@Sun.COM ddi_dma_freehdl, 104*10187SKrishna.Elango@Sun.COM ddi_dma_bindhdl, 105*10187SKrishna.Elango@Sun.COM ddi_dma_unbindhdl, 106*10187SKrishna.Elango@Sun.COM ddi_dma_flush, 107*10187SKrishna.Elango@Sun.COM ddi_dma_win, 108*10187SKrishna.Elango@Sun.COM pcieb_dma_mctl, 109*10187SKrishna.Elango@Sun.COM pcieb_ctlops, 110*10187SKrishna.Elango@Sun.COM ddi_bus_prop_op, 111*10187SKrishna.Elango@Sun.COM ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ 112*10187SKrishna.Elango@Sun.COM ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ 113*10187SKrishna.Elango@Sun.COM ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ 114*10187SKrishna.Elango@Sun.COM ndi_post_event, /* (*bus_post_event)(); */ 115*10187SKrishna.Elango@Sun.COM NULL, /* (*bus_intr_ctl)(); */ 116*10187SKrishna.Elango@Sun.COM NULL, /* (*bus_config)(); */ 117*10187SKrishna.Elango@Sun.COM NULL, /* (*bus_unconfig)(); */ 118*10187SKrishna.Elango@Sun.COM pcieb_fm_init_child, /* (*bus_fm_init)(); */ 119*10187SKrishna.Elango@Sun.COM NULL, /* (*bus_fm_fini)(); */ 120*10187SKrishna.Elango@Sun.COM i_ndi_busop_access_enter, /* (*bus_fm_access_enter)(); */ 121*10187SKrishna.Elango@Sun.COM i_ndi_busop_access_exit, /* (*bus_fm_access_exit)(); */ 122*10187SKrishna.Elango@Sun.COM pcie_bus_power, /* (*bus_power)(); */ 123*10187SKrishna.Elango@Sun.COM pcieb_intr_ops /* (*bus_intr_op)(); */ 124*10187SKrishna.Elango@Sun.COM }; 125*10187SKrishna.Elango@Sun.COM 126*10187SKrishna.Elango@Sun.COM static int pcieb_open(dev_t *, int, int, cred_t *); 127*10187SKrishna.Elango@Sun.COM static int pcieb_close(dev_t, int, int, cred_t *); 128*10187SKrishna.Elango@Sun.COM static int pcieb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 129*10187SKrishna.Elango@Sun.COM static int pcieb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 130*10187SKrishna.Elango@Sun.COM caddr_t, int *); 131*10187SKrishna.Elango@Sun.COM static int pcieb_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 132*10187SKrishna.Elango@Sun.COM static uint_t pcieb_intr_handler(caddr_t arg1, caddr_t arg2); 133*10187SKrishna.Elango@Sun.COM 134*10187SKrishna.Elango@Sun.COM /* PM related functions */ 135*10187SKrishna.Elango@Sun.COM static int pcieb_pwr_setup(dev_info_t *dip); 136*10187SKrishna.Elango@Sun.COM static int pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p); 137*10187SKrishna.Elango@Sun.COM static void pcieb_pwr_teardown(dev_info_t *dip); 138*10187SKrishna.Elango@Sun.COM static int pcieb_pwr_disable(dev_info_t *dip); 139*10187SKrishna.Elango@Sun.COM 140*10187SKrishna.Elango@Sun.COM /* Hotplug related functions */ 141*10187SKrishna.Elango@Sun.COM static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle); 142*10187SKrishna.Elango@Sun.COM static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle); 143*10187SKrishna.Elango@Sun.COM static int pcieb_init_hotplug(pcieb_devstate_t *pcieb); 144*10187SKrishna.Elango@Sun.COM static void pcieb_id_props(pcieb_devstate_t *pcieb); 145*10187SKrishna.Elango@Sun.COM 146*10187SKrishna.Elango@Sun.COM /* 147*10187SKrishna.Elango@Sun.COM * soft state pointer 148*10187SKrishna.Elango@Sun.COM */ 149*10187SKrishna.Elango@Sun.COM void *pcieb_state; 150*10187SKrishna.Elango@Sun.COM 151*10187SKrishna.Elango@Sun.COM static struct cb_ops pcieb_cb_ops = { 152*10187SKrishna.Elango@Sun.COM pcieb_open, /* open */ 153*10187SKrishna.Elango@Sun.COM pcieb_close, /* close */ 154*10187SKrishna.Elango@Sun.COM nodev, /* strategy */ 155*10187SKrishna.Elango@Sun.COM nodev, /* print */ 156*10187SKrishna.Elango@Sun.COM nodev, /* dump */ 157*10187SKrishna.Elango@Sun.COM nodev, /* read */ 158*10187SKrishna.Elango@Sun.COM nodev, /* write */ 159*10187SKrishna.Elango@Sun.COM pcieb_ioctl, /* ioctl */ 160*10187SKrishna.Elango@Sun.COM nodev, /* devmap */ 161*10187SKrishna.Elango@Sun.COM nodev, /* mmap */ 162*10187SKrishna.Elango@Sun.COM nodev, /* segmap */ 163*10187SKrishna.Elango@Sun.COM nochpoll, /* poll */ 164*10187SKrishna.Elango@Sun.COM pcieb_prop_op, /* cb_prop_op */ 165*10187SKrishna.Elango@Sun.COM NULL, /* streamtab */ 166*10187SKrishna.Elango@Sun.COM D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 167*10187SKrishna.Elango@Sun.COM CB_REV, /* rev */ 168*10187SKrishna.Elango@Sun.COM nodev, /* int (*cb_aread)() */ 169*10187SKrishna.Elango@Sun.COM nodev /* int (*cb_awrite)() */ 170*10187SKrishna.Elango@Sun.COM }; 171*10187SKrishna.Elango@Sun.COM 172*10187SKrishna.Elango@Sun.COM static int pcieb_probe(dev_info_t *); 173*10187SKrishna.Elango@Sun.COM static int pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 174*10187SKrishna.Elango@Sun.COM static int pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 175*10187SKrishna.Elango@Sun.COM 176*10187SKrishna.Elango@Sun.COM static struct dev_ops pcieb_ops = { 177*10187SKrishna.Elango@Sun.COM DEVO_REV, /* devo_rev */ 178*10187SKrishna.Elango@Sun.COM 0, /* refcnt */ 179*10187SKrishna.Elango@Sun.COM pcieb_info, /* info */ 180*10187SKrishna.Elango@Sun.COM nulldev, /* identify */ 181*10187SKrishna.Elango@Sun.COM pcieb_probe, /* probe */ 182*10187SKrishna.Elango@Sun.COM pcieb_attach, /* attach */ 183*10187SKrishna.Elango@Sun.COM pcieb_detach, /* detach */ 184*10187SKrishna.Elango@Sun.COM nulldev, /* reset */ 185*10187SKrishna.Elango@Sun.COM &pcieb_cb_ops, /* driver operations */ 186*10187SKrishna.Elango@Sun.COM &pcieb_bus_ops, /* bus operations */ 187*10187SKrishna.Elango@Sun.COM pcie_power, /* power */ 188*10187SKrishna.Elango@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 189*10187SKrishna.Elango@Sun.COM }; 190*10187SKrishna.Elango@Sun.COM 191*10187SKrishna.Elango@Sun.COM /* 192*10187SKrishna.Elango@Sun.COM * Module linkage information for the kernel. 193*10187SKrishna.Elango@Sun.COM */ 194*10187SKrishna.Elango@Sun.COM 195*10187SKrishna.Elango@Sun.COM static struct modldrv modldrv = { 196*10187SKrishna.Elango@Sun.COM &mod_driverops, /* Type of module */ 197*10187SKrishna.Elango@Sun.COM "PCIe to PCI nexus driver", 198*10187SKrishna.Elango@Sun.COM &pcieb_ops, /* driver ops */ 199*10187SKrishna.Elango@Sun.COM }; 200*10187SKrishna.Elango@Sun.COM 201*10187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = { 202*10187SKrishna.Elango@Sun.COM MODREV_1, 203*10187SKrishna.Elango@Sun.COM (void *)&modldrv, 204*10187SKrishna.Elango@Sun.COM NULL 205*10187SKrishna.Elango@Sun.COM }; 206*10187SKrishna.Elango@Sun.COM 207*10187SKrishna.Elango@Sun.COM /* 208*10187SKrishna.Elango@Sun.COM * forward function declarations: 209*10187SKrishna.Elango@Sun.COM */ 210*10187SKrishna.Elango@Sun.COM static void pcieb_uninitchild(dev_info_t *); 211*10187SKrishna.Elango@Sun.COM static int pcieb_initchild(dev_info_t *child); 212*10187SKrishna.Elango@Sun.COM static void pcieb_create_ranges_prop(dev_info_t *, ddi_acc_handle_t); 213*10187SKrishna.Elango@Sun.COM static boolean_t pcieb_is_pcie_device_type(dev_info_t *dip); 214*10187SKrishna.Elango@Sun.COM 215*10187SKrishna.Elango@Sun.COM /* interrupt related declarations */ 216*10187SKrishna.Elango@Sun.COM static int pcieb_msi_supported(dev_info_t *); 217*10187SKrishna.Elango@Sun.COM static int pcieb_intr_attach(pcieb_devstate_t *pcieb); 218*10187SKrishna.Elango@Sun.COM static int pcieb_intr_init(pcieb_devstate_t *pcieb_p, int intr_type); 219*10187SKrishna.Elango@Sun.COM static void pcieb_intr_fini(pcieb_devstate_t *pcieb_p); 220*10187SKrishna.Elango@Sun.COM 221*10187SKrishna.Elango@Sun.COM int 222*10187SKrishna.Elango@Sun.COM _init(void) 223*10187SKrishna.Elango@Sun.COM { 224*10187SKrishna.Elango@Sun.COM int e; 225*10187SKrishna.Elango@Sun.COM 226*10187SKrishna.Elango@Sun.COM if ((e = ddi_soft_state_init(&pcieb_state, sizeof (pcieb_devstate_t), 227*10187SKrishna.Elango@Sun.COM 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 228*10187SKrishna.Elango@Sun.COM ddi_soft_state_fini(&pcieb_state); 229*10187SKrishna.Elango@Sun.COM return (e); 230*10187SKrishna.Elango@Sun.COM } 231*10187SKrishna.Elango@Sun.COM 232*10187SKrishna.Elango@Sun.COM int 233*10187SKrishna.Elango@Sun.COM _fini(void) 234*10187SKrishna.Elango@Sun.COM { 235*10187SKrishna.Elango@Sun.COM int e; 236*10187SKrishna.Elango@Sun.COM 237*10187SKrishna.Elango@Sun.COM if ((e = mod_remove(&modlinkage)) == 0) { 238*10187SKrishna.Elango@Sun.COM ddi_soft_state_fini(&pcieb_state); 239*10187SKrishna.Elango@Sun.COM } 240*10187SKrishna.Elango@Sun.COM return (e); 241*10187SKrishna.Elango@Sun.COM } 242*10187SKrishna.Elango@Sun.COM 243*10187SKrishna.Elango@Sun.COM int 244*10187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop) 245*10187SKrishna.Elango@Sun.COM { 246*10187SKrishna.Elango@Sun.COM return (mod_info(&modlinkage, modinfop)); 247*10187SKrishna.Elango@Sun.COM } 248*10187SKrishna.Elango@Sun.COM 249*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 250*10187SKrishna.Elango@Sun.COM static int 251*10187SKrishna.Elango@Sun.COM pcieb_probe(dev_info_t *devi) 252*10187SKrishna.Elango@Sun.COM { 253*10187SKrishna.Elango@Sun.COM return (DDI_PROBE_SUCCESS); 254*10187SKrishna.Elango@Sun.COM } 255*10187SKrishna.Elango@Sun.COM 256*10187SKrishna.Elango@Sun.COM static int 257*10187SKrishna.Elango@Sun.COM pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 258*10187SKrishna.Elango@Sun.COM { 259*10187SKrishna.Elango@Sun.COM int instance; 260*10187SKrishna.Elango@Sun.COM char device_type[8]; 261*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb; 262*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(devi); 263*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl; 264*10187SKrishna.Elango@Sun.COM uint8_t dev_type = bus_p->bus_dev_type; 265*10187SKrishna.Elango@Sun.COM 266*10187SKrishna.Elango@Sun.COM switch (cmd) { 267*10187SKrishna.Elango@Sun.COM case DDI_RESUME: 268*10187SKrishna.Elango@Sun.COM (void) pcie_pwr_resume(devi); 269*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 270*10187SKrishna.Elango@Sun.COM 271*10187SKrishna.Elango@Sun.COM default: 272*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 273*10187SKrishna.Elango@Sun.COM 274*10187SKrishna.Elango@Sun.COM case DDI_ATTACH: 275*10187SKrishna.Elango@Sun.COM break; 276*10187SKrishna.Elango@Sun.COM } 277*10187SKrishna.Elango@Sun.COM 278*10187SKrishna.Elango@Sun.COM if (!(PCIE_IS_BDG(bus_p))) { 279*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, devi, "This is not a switch or" 280*10187SKrishna.Elango@Sun.COM " bridge\n"); 281*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 282*10187SKrishna.Elango@Sun.COM } 283*10187SKrishna.Elango@Sun.COM 284*10187SKrishna.Elango@Sun.COM /* 285*10187SKrishna.Elango@Sun.COM * If PCIE_LINKCTL_LINK_DISABLE bit in the PCIe Config 286*10187SKrishna.Elango@Sun.COM * Space (PCIe Capability Link Control Register) is set, 287*10187SKrishna.Elango@Sun.COM * then do not bind the driver. 288*10187SKrishna.Elango@Sun.COM */ 289*10187SKrishna.Elango@Sun.COM if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & PCIE_LINKCTL_LINK_DISABLE) 290*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 291*10187SKrishna.Elango@Sun.COM 292*10187SKrishna.Elango@Sun.COM /* 293*10187SKrishna.Elango@Sun.COM * Allocate and get soft state structure. 294*10187SKrishna.Elango@Sun.COM */ 295*10187SKrishna.Elango@Sun.COM instance = ddi_get_instance(devi); 296*10187SKrishna.Elango@Sun.COM if (ddi_soft_state_zalloc(pcieb_state, instance) != DDI_SUCCESS) 297*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 298*10187SKrishna.Elango@Sun.COM pcieb = ddi_get_soft_state(pcieb_state, instance); 299*10187SKrishna.Elango@Sun.COM pcieb->pcieb_dip = devi; 300*10187SKrishna.Elango@Sun.COM pcieb->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED; 301*10187SKrishna.Elango@Sun.COM 302*10187SKrishna.Elango@Sun.COM if ((pcieb_fm_init(pcieb)) != DDI_SUCCESS) { 303*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, devi, "Failed in pcieb_fm_init\n"); 304*10187SKrishna.Elango@Sun.COM goto fail; 305*10187SKrishna.Elango@Sun.COM } 306*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags |= PCIEB_INIT_FM; 307*10187SKrishna.Elango@Sun.COM 308*10187SKrishna.Elango@Sun.COM mutex_init(&pcieb->pcieb_mutex, NULL, MUTEX_DRIVER, NULL); 309*10187SKrishna.Elango@Sun.COM mutex_init(&pcieb->pcieb_err_mutex, NULL, MUTEX_DRIVER, 310*10187SKrishna.Elango@Sun.COM (void *)pcieb->pcieb_fm_ibc); 311*10187SKrishna.Elango@Sun.COM mutex_init(&pcieb->pcieb_peek_poke_mutex, NULL, MUTEX_DRIVER, 312*10187SKrishna.Elango@Sun.COM (void *)pcieb->pcieb_fm_ibc); 313*10187SKrishna.Elango@Sun.COM 314*10187SKrishna.Elango@Sun.COM /* create special properties for device identification */ 315*10187SKrishna.Elango@Sun.COM pcieb_id_props(pcieb); 316*10187SKrishna.Elango@Sun.COM 317*10187SKrishna.Elango@Sun.COM /* 318*10187SKrishna.Elango@Sun.COM * Power management setup. This also makes sure that switch/bridge 319*10187SKrishna.Elango@Sun.COM * is at D0 during attach. 320*10187SKrishna.Elango@Sun.COM */ 321*10187SKrishna.Elango@Sun.COM if (pwr_common_setup(devi) != DDI_SUCCESS) { 322*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, devi, "pwr_common_setup failed\n"); 323*10187SKrishna.Elango@Sun.COM goto fail; 324*10187SKrishna.Elango@Sun.COM } 325*10187SKrishna.Elango@Sun.COM 326*10187SKrishna.Elango@Sun.COM if (pcieb_pwr_setup(devi) != DDI_SUCCESS) { 327*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, devi, "pxb_pwr_setup failed \n"); 328*10187SKrishna.Elango@Sun.COM goto fail; 329*10187SKrishna.Elango@Sun.COM } 330*10187SKrishna.Elango@Sun.COM 331*10187SKrishna.Elango@Sun.COM /* 332*10187SKrishna.Elango@Sun.COM * Make sure the "device_type" property exists. 333*10187SKrishna.Elango@Sun.COM */ 334*10187SKrishna.Elango@Sun.COM if (pcieb_is_pcie_device_type(devi)) 335*10187SKrishna.Elango@Sun.COM (void) strcpy(device_type, "pciex"); 336*10187SKrishna.Elango@Sun.COM else 337*10187SKrishna.Elango@Sun.COM (void) strcpy(device_type, "pci"); 338*10187SKrishna.Elango@Sun.COM 339*10187SKrishna.Elango@Sun.COM (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 340*10187SKrishna.Elango@Sun.COM "device_type", device_type); 341*10187SKrishna.Elango@Sun.COM 342*10187SKrishna.Elango@Sun.COM /* 343*10187SKrishna.Elango@Sun.COM * Check whether the "ranges" property is present. 344*10187SKrishna.Elango@Sun.COM * Otherwise create the ranges property by reading 345*10187SKrishna.Elango@Sun.COM * the configuration registers 346*10187SKrishna.Elango@Sun.COM */ 347*10187SKrishna.Elango@Sun.COM if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 348*10187SKrishna.Elango@Sun.COM "ranges") == 0) { 349*10187SKrishna.Elango@Sun.COM pcieb_create_ranges_prop(devi, config_handle); 350*10187SKrishna.Elango@Sun.COM } 351*10187SKrishna.Elango@Sun.COM 352*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCI_BDG(bus_p)) 353*10187SKrishna.Elango@Sun.COM pcieb_set_pci_perf_parameters(devi, config_handle); 354*10187SKrishna.Elango@Sun.COM 355*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX 356*10187SKrishna.Elango@Sun.COM pcieb_attach_plx_workarounds(pcieb); 357*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 358*10187SKrishna.Elango@Sun.COM 359*10187SKrishna.Elango@Sun.COM /* Initialize hotplug */ 360*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hotplug_capable = B_FALSE; 361*10187SKrishna.Elango@Sun.COM 362*10187SKrishna.Elango@Sun.COM if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) || 363*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) || 364*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) || 365*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) { 366*10187SKrishna.Elango@Sun.COM (void) pcieb_init_hotplug(pcieb); 367*10187SKrishna.Elango@Sun.COM } 368*10187SKrishna.Elango@Sun.COM 369*10187SKrishna.Elango@Sun.COM /* 370*10187SKrishna.Elango@Sun.COM * Initialize interrupt handlers. Ignore return value. 371*10187SKrishna.Elango@Sun.COM */ 372*10187SKrishna.Elango@Sun.COM (void) pcieb_intr_attach(pcieb); 373*10187SKrishna.Elango@Sun.COM 374*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_hotplug_capable == B_FALSE) { 375*10187SKrishna.Elango@Sun.COM /* 376*10187SKrishna.Elango@Sun.COM * (for non hotplug bus) this would create ":devctl" minor 377*10187SKrishna.Elango@Sun.COM * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 378*10187SKrishna.Elango@Sun.COM * to this bus. 379*10187SKrishna.Elango@Sun.COM */ 380*10187SKrishna.Elango@Sun.COM if (ddi_create_minor_node(devi, "devctl", S_IFCHR, 381*10187SKrishna.Elango@Sun.COM PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR), 382*10187SKrishna.Elango@Sun.COM DDI_NT_NEXUS, 0) != DDI_SUCCESS) 383*10187SKrishna.Elango@Sun.COM goto fail; 384*10187SKrishna.Elango@Sun.COM } 385*10187SKrishna.Elango@Sun.COM 386*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, devi, 387*10187SKrishna.Elango@Sun.COM "pcieb_attach: this nexus %s hotplug slots\n", 388*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hotplug_capable == B_TRUE ? "has":"has no"); 389*10187SKrishna.Elango@Sun.COM 390*10187SKrishna.Elango@Sun.COM /* Do any platform specific workarounds needed at this time */ 391*10187SKrishna.Elango@Sun.COM pcieb_plat_attach_workaround(devi); 392*10187SKrishna.Elango@Sun.COM 393*10187SKrishna.Elango@Sun.COM /* 394*10187SKrishna.Elango@Sun.COM * If this is a root port, determine and set the max payload size. 395*10187SKrishna.Elango@Sun.COM * Since this will involve scanning the fabric, all error enabling 396*10187SKrishna.Elango@Sun.COM * and sw workarounds should be in place before doing this. 397*10187SKrishna.Elango@Sun.COM */ 398*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 399*10187SKrishna.Elango@Sun.COM pcie_init_root_port_mps(devi); 400*10187SKrishna.Elango@Sun.COM 401*10187SKrishna.Elango@Sun.COM ddi_report_dev(devi); 402*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 403*10187SKrishna.Elango@Sun.COM 404*10187SKrishna.Elango@Sun.COM fail: 405*10187SKrishna.Elango@Sun.COM (void) pcieb_detach(devi, DDI_DETACH); 406*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 407*10187SKrishna.Elango@Sun.COM } 408*10187SKrishna.Elango@Sun.COM 409*10187SKrishna.Elango@Sun.COM static int 410*10187SKrishna.Elango@Sun.COM pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 411*10187SKrishna.Elango@Sun.COM { 412*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb; 413*10187SKrishna.Elango@Sun.COM int error = DDI_SUCCESS; 414*10187SKrishna.Elango@Sun.COM 415*10187SKrishna.Elango@Sun.COM switch (cmd) { 416*10187SKrishna.Elango@Sun.COM case DDI_SUSPEND: 417*10187SKrishna.Elango@Sun.COM error = pcie_pwr_suspend(devi); 418*10187SKrishna.Elango@Sun.COM return (error); 419*10187SKrishna.Elango@Sun.COM 420*10187SKrishna.Elango@Sun.COM case DDI_DETACH: 421*10187SKrishna.Elango@Sun.COM break; 422*10187SKrishna.Elango@Sun.COM 423*10187SKrishna.Elango@Sun.COM default: 424*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 425*10187SKrishna.Elango@Sun.COM } 426*10187SKrishna.Elango@Sun.COM 427*10187SKrishna.Elango@Sun.COM pcieb = ddi_get_soft_state(pcieb_state, ddi_get_instance(devi)); 428*10187SKrishna.Elango@Sun.COM 429*10187SKrishna.Elango@Sun.COM /* remove interrupt handlers */ 430*10187SKrishna.Elango@Sun.COM pcieb_intr_fini(pcieb); 431*10187SKrishna.Elango@Sun.COM 432*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_hotplug_capable == B_TRUE) { 433*10187SKrishna.Elango@Sun.COM if (pcihp_uninit(devi) == DDI_FAILURE) 434*10187SKrishna.Elango@Sun.COM error = DDI_FAILURE; 435*10187SKrishna.Elango@Sun.COM 436*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_hpc_type == HPC_PCIE) 437*10187SKrishna.Elango@Sun.COM (void) pciehpc_uninit(devi); 438*10187SKrishna.Elango@Sun.COM else if (pcieb->pcieb_hpc_type == HPC_SHPC) 439*10187SKrishna.Elango@Sun.COM (void) pcishpc_uninit(devi); 440*10187SKrishna.Elango@Sun.COM } else { 441*10187SKrishna.Elango@Sun.COM ddi_remove_minor_node(devi, "devctl"); 442*10187SKrishna.Elango@Sun.COM } 443*10187SKrishna.Elango@Sun.COM 444*10187SKrishna.Elango@Sun.COM (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); 445*10187SKrishna.Elango@Sun.COM 446*10187SKrishna.Elango@Sun.COM (void) ndi_prop_remove(DDI_DEV_T_NONE, pcieb->pcieb_dip, 447*10187SKrishna.Elango@Sun.COM "pcie_ce_mask"); 448*10187SKrishna.Elango@Sun.COM 449*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_init_flags & PCIEB_INIT_FM) 450*10187SKrishna.Elango@Sun.COM pcieb_fm_fini(pcieb); 451*10187SKrishna.Elango@Sun.COM 452*10187SKrishna.Elango@Sun.COM pcieb_pwr_teardown(devi); 453*10187SKrishna.Elango@Sun.COM pwr_common_teardown(devi); 454*10187SKrishna.Elango@Sun.COM 455*10187SKrishna.Elango@Sun.COM mutex_destroy(&pcieb->pcieb_peek_poke_mutex); 456*10187SKrishna.Elango@Sun.COM mutex_destroy(&pcieb->pcieb_err_mutex); 457*10187SKrishna.Elango@Sun.COM mutex_destroy(&pcieb->pcieb_mutex); 458*10187SKrishna.Elango@Sun.COM 459*10187SKrishna.Elango@Sun.COM /* 460*10187SKrishna.Elango@Sun.COM * And finally free the per-pci soft state. 461*10187SKrishna.Elango@Sun.COM */ 462*10187SKrishna.Elango@Sun.COM ddi_soft_state_free(pcieb_state, ddi_get_instance(devi)); 463*10187SKrishna.Elango@Sun.COM 464*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 465*10187SKrishna.Elango@Sun.COM } 466*10187SKrishna.Elango@Sun.COM 467*10187SKrishna.Elango@Sun.COM static int 468*10187SKrishna.Elango@Sun.COM pcieb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 469*10187SKrishna.Elango@Sun.COM off_t offset, off_t len, caddr_t *vaddrp) 470*10187SKrishna.Elango@Sun.COM { 471*10187SKrishna.Elango@Sun.COM dev_info_t *pdip; 472*10187SKrishna.Elango@Sun.COM 473*10187SKrishna.Elango@Sun.COM pdip = (dev_info_t *)DEVI(dip)->devi_parent; 474*10187SKrishna.Elango@Sun.COM return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip, rdip, mp, 475*10187SKrishna.Elango@Sun.COM offset, len, vaddrp)); 476*10187SKrishna.Elango@Sun.COM } 477*10187SKrishna.Elango@Sun.COM 478*10187SKrishna.Elango@Sun.COM static int 479*10187SKrishna.Elango@Sun.COM pcieb_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 480*10187SKrishna.Elango@Sun.COM void *arg, void *result) 481*10187SKrishna.Elango@Sun.COM { 482*10187SKrishna.Elango@Sun.COM pci_regspec_t *drv_regp; 483*10187SKrishna.Elango@Sun.COM int reglen; 484*10187SKrishna.Elango@Sun.COM int rn; 485*10187SKrishna.Elango@Sun.COM int totreg; 486*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, 487*10187SKrishna.Elango@Sun.COM ddi_get_instance(dip)); 488*10187SKrishna.Elango@Sun.COM struct detachspec *ds; 489*10187SKrishna.Elango@Sun.COM struct attachspec *as; 490*10187SKrishna.Elango@Sun.COM 491*10187SKrishna.Elango@Sun.COM switch (ctlop) { 492*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_REPORTDEV: 493*10187SKrishna.Elango@Sun.COM if (rdip == (dev_info_t *)0) 494*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 495*10187SKrishna.Elango@Sun.COM cmn_err(CE_CONT, "?PCIE-device: %s@%s, %s%d\n", 496*10187SKrishna.Elango@Sun.COM ddi_node_name(rdip), ddi_get_name_addr(rdip), 497*10187SKrishna.Elango@Sun.COM ddi_driver_name(rdip), 498*10187SKrishna.Elango@Sun.COM ddi_get_instance(rdip)); 499*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 500*10187SKrishna.Elango@Sun.COM 501*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_INITCHILD: 502*10187SKrishna.Elango@Sun.COM return (pcieb_initchild((dev_info_t *)arg)); 503*10187SKrishna.Elango@Sun.COM 504*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_UNINITCHILD: 505*10187SKrishna.Elango@Sun.COM pcieb_uninitchild((dev_info_t *)arg); 506*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 507*10187SKrishna.Elango@Sun.COM 508*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_SIDDEV: 509*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 510*10187SKrishna.Elango@Sun.COM 511*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_REGSIZE: 512*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_NREGS: 513*10187SKrishna.Elango@Sun.COM if (rdip == (dev_info_t *)0) 514*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 515*10187SKrishna.Elango@Sun.COM break; 516*10187SKrishna.Elango@Sun.COM 517*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_PEEK: 518*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_POKE: 519*10187SKrishna.Elango@Sun.COM return (pcieb_plat_peekpoke(dip, rdip, ctlop, arg, result)); 520*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_ATTACH: 521*10187SKrishna.Elango@Sun.COM if (!pcie_is_child(dip, rdip)) 522*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 523*10187SKrishna.Elango@Sun.COM 524*10187SKrishna.Elango@Sun.COM as = (struct attachspec *)arg; 525*10187SKrishna.Elango@Sun.COM switch (as->when) { 526*10187SKrishna.Elango@Sun.COM case DDI_PRE: 527*10187SKrishna.Elango@Sun.COM if (as->cmd == DDI_RESUME) { 528*10187SKrishna.Elango@Sun.COM pcie_clear_errors(rdip); 529*10187SKrishna.Elango@Sun.COM if (pcieb_plat_ctlops(rdip, ctlop, arg) != 530*10187SKrishna.Elango@Sun.COM DDI_SUCCESS) 531*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 532*10187SKrishna.Elango@Sun.COM } 533*10187SKrishna.Elango@Sun.COM 534*10187SKrishna.Elango@Sun.COM if (as->cmd == DDI_ATTACH) 535*10187SKrishna.Elango@Sun.COM return (pcie_pm_hold(dip)); 536*10187SKrishna.Elango@Sun.COM 537*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 538*10187SKrishna.Elango@Sun.COM 539*10187SKrishna.Elango@Sun.COM case DDI_POST: 540*10187SKrishna.Elango@Sun.COM if (as->cmd == DDI_ATTACH && as->result != DDI_SUCCESS) 541*10187SKrishna.Elango@Sun.COM pcie_pm_release(dip); 542*10187SKrishna.Elango@Sun.COM 543*10187SKrishna.Elango@Sun.COM if (as->result == DDI_SUCCESS) { 544*10187SKrishna.Elango@Sun.COM pf_init(rdip, (void *)pcieb->pcieb_fm_ibc, 545*10187SKrishna.Elango@Sun.COM as->cmd); 546*10187SKrishna.Elango@Sun.COM 547*10187SKrishna.Elango@Sun.COM (void) pcieb_plat_ctlops(rdip, ctlop, arg); 548*10187SKrishna.Elango@Sun.COM } 549*10187SKrishna.Elango@Sun.COM 550*10187SKrishna.Elango@Sun.COM /* 551*10187SKrishna.Elango@Sun.COM * For empty hotplug-capable slots, we should explicitly 552*10187SKrishna.Elango@Sun.COM * disable the errors, so that we won't panic upon 553*10187SKrishna.Elango@Sun.COM * unsupported hotplug messages. 554*10187SKrishna.Elango@Sun.COM */ 555*10187SKrishna.Elango@Sun.COM if ((!ddi_prop_exists(DDI_DEV_T_ANY, rdip, 556*10187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "hotplug-capable")) || 557*10187SKrishna.Elango@Sun.COM ddi_get_child(rdip)) { 558*10187SKrishna.Elango@Sun.COM (void) pcie_postattach_child(rdip); 559*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 560*10187SKrishna.Elango@Sun.COM } 561*10187SKrishna.Elango@Sun.COM 562*10187SKrishna.Elango@Sun.COM pcie_disable_errors(rdip); 563*10187SKrishna.Elango@Sun.COM 564*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 565*10187SKrishna.Elango@Sun.COM default: 566*10187SKrishna.Elango@Sun.COM break; 567*10187SKrishna.Elango@Sun.COM } 568*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 569*10187SKrishna.Elango@Sun.COM 570*10187SKrishna.Elango@Sun.COM case DDI_CTLOPS_DETACH: 571*10187SKrishna.Elango@Sun.COM if (!pcie_is_child(dip, rdip)) 572*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 573*10187SKrishna.Elango@Sun.COM 574*10187SKrishna.Elango@Sun.COM ds = (struct detachspec *)arg; 575*10187SKrishna.Elango@Sun.COM switch (ds->when) { 576*10187SKrishna.Elango@Sun.COM case DDI_PRE: 577*10187SKrishna.Elango@Sun.COM pf_fini(rdip, ds->cmd); 578*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 579*10187SKrishna.Elango@Sun.COM 580*10187SKrishna.Elango@Sun.COM case DDI_POST: 581*10187SKrishna.Elango@Sun.COM if (pcieb_plat_ctlops(rdip, ctlop, arg) != DDI_SUCCESS) 582*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 583*10187SKrishna.Elango@Sun.COM if (ds->cmd == DDI_DETACH && 584*10187SKrishna.Elango@Sun.COM ds->result == DDI_SUCCESS) { 585*10187SKrishna.Elango@Sun.COM return (pcie_pm_remove_child(dip, rdip)); 586*10187SKrishna.Elango@Sun.COM } 587*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 588*10187SKrishna.Elango@Sun.COM default: 589*10187SKrishna.Elango@Sun.COM break; 590*10187SKrishna.Elango@Sun.COM } 591*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 592*10187SKrishna.Elango@Sun.COM default: 593*10187SKrishna.Elango@Sun.COM return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 594*10187SKrishna.Elango@Sun.COM } 595*10187SKrishna.Elango@Sun.COM 596*10187SKrishna.Elango@Sun.COM *(int *)result = 0; 597*10187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, 598*10187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&drv_regp, 599*10187SKrishna.Elango@Sun.COM ®len) != DDI_SUCCESS) 600*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 601*10187SKrishna.Elango@Sun.COM 602*10187SKrishna.Elango@Sun.COM totreg = reglen / sizeof (pci_regspec_t); 603*10187SKrishna.Elango@Sun.COM if (ctlop == DDI_CTLOPS_NREGS) 604*10187SKrishna.Elango@Sun.COM *(int *)result = totreg; 605*10187SKrishna.Elango@Sun.COM else if (ctlop == DDI_CTLOPS_REGSIZE) { 606*10187SKrishna.Elango@Sun.COM rn = *(int *)arg; 607*10187SKrishna.Elango@Sun.COM if (rn >= totreg) { 608*10187SKrishna.Elango@Sun.COM kmem_free(drv_regp, reglen); 609*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 610*10187SKrishna.Elango@Sun.COM } 611*10187SKrishna.Elango@Sun.COM 612*10187SKrishna.Elango@Sun.COM *(off_t *)result = drv_regp[rn].pci_size_low | 613*10187SKrishna.Elango@Sun.COM ((uint64_t)drv_regp[rn].pci_size_hi << 32); 614*10187SKrishna.Elango@Sun.COM } 615*10187SKrishna.Elango@Sun.COM 616*10187SKrishna.Elango@Sun.COM kmem_free(drv_regp, reglen); 617*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 618*10187SKrishna.Elango@Sun.COM } 619*10187SKrishna.Elango@Sun.COM 620*10187SKrishna.Elango@Sun.COM /* 621*10187SKrishna.Elango@Sun.COM * name_child 622*10187SKrishna.Elango@Sun.COM * 623*10187SKrishna.Elango@Sun.COM * This function is called from init_child to name a node. It is 624*10187SKrishna.Elango@Sun.COM * also passed as a callback for node merging functions. 625*10187SKrishna.Elango@Sun.COM * 626*10187SKrishna.Elango@Sun.COM * return value: DDI_SUCCESS, DDI_FAILURE 627*10187SKrishna.Elango@Sun.COM */ 628*10187SKrishna.Elango@Sun.COM static int 629*10187SKrishna.Elango@Sun.COM pcieb_name_child(dev_info_t *child, char *name, int namelen) 630*10187SKrishna.Elango@Sun.COM { 631*10187SKrishna.Elango@Sun.COM pci_regspec_t *pci_rp; 632*10187SKrishna.Elango@Sun.COM uint_t slot, func; 633*10187SKrishna.Elango@Sun.COM char **unit_addr; 634*10187SKrishna.Elango@Sun.COM uint_t n; 635*10187SKrishna.Elango@Sun.COM 636*10187SKrishna.Elango@Sun.COM /* 637*10187SKrishna.Elango@Sun.COM * For .conf nodes, use unit-address property as name 638*10187SKrishna.Elango@Sun.COM */ 639*10187SKrishna.Elango@Sun.COM if (ndi_dev_is_persistent_node(child) == 0) { 640*10187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 641*10187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 642*10187SKrishna.Elango@Sun.COM DDI_PROP_SUCCESS) { 643*10187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, 644*10187SKrishna.Elango@Sun.COM "cannot find unit-address in %s.conf", 645*10187SKrishna.Elango@Sun.COM ddi_driver_name(child)); 646*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 647*10187SKrishna.Elango@Sun.COM } 648*10187SKrishna.Elango@Sun.COM if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 649*10187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "unit-address property in %s.conf" 650*10187SKrishna.Elango@Sun.COM " not well-formed", ddi_driver_name(child)); 651*10187SKrishna.Elango@Sun.COM ddi_prop_free(unit_addr); 652*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 653*10187SKrishna.Elango@Sun.COM } 654*10187SKrishna.Elango@Sun.COM (void) snprintf(name, namelen, "%s", *unit_addr); 655*10187SKrishna.Elango@Sun.COM ddi_prop_free(unit_addr); 656*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 657*10187SKrishna.Elango@Sun.COM } 658*10187SKrishna.Elango@Sun.COM 659*10187SKrishna.Elango@Sun.COM /* 660*10187SKrishna.Elango@Sun.COM * Get the address portion of the node name based on 661*10187SKrishna.Elango@Sun.COM * the function and device number. 662*10187SKrishna.Elango@Sun.COM */ 663*10187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 664*10187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) { 665*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 666*10187SKrishna.Elango@Sun.COM } 667*10187SKrishna.Elango@Sun.COM 668*10187SKrishna.Elango@Sun.COM /* copy the device identifications */ 669*10187SKrishna.Elango@Sun.COM slot = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); 670*10187SKrishna.Elango@Sun.COM func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi); 671*10187SKrishna.Elango@Sun.COM 672*10187SKrishna.Elango@Sun.COM if (func != 0) 673*10187SKrishna.Elango@Sun.COM (void) snprintf(name, namelen, "%x,%x", slot, func); 674*10187SKrishna.Elango@Sun.COM else 675*10187SKrishna.Elango@Sun.COM (void) snprintf(name, namelen, "%x", slot); 676*10187SKrishna.Elango@Sun.COM 677*10187SKrishna.Elango@Sun.COM ddi_prop_free(pci_rp); 678*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 679*10187SKrishna.Elango@Sun.COM } 680*10187SKrishna.Elango@Sun.COM 681*10187SKrishna.Elango@Sun.COM static int 682*10187SKrishna.Elango@Sun.COM pcieb_initchild(dev_info_t *child) 683*10187SKrishna.Elango@Sun.COM { 684*10187SKrishna.Elango@Sun.COM char name[MAXNAMELEN]; 685*10187SKrishna.Elango@Sun.COM int result = DDI_FAILURE; 686*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb = 687*10187SKrishna.Elango@Sun.COM (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state, 688*10187SKrishna.Elango@Sun.COM ddi_get_instance(ddi_get_parent(child))); 689*10187SKrishna.Elango@Sun.COM 690*10187SKrishna.Elango@Sun.COM /* 691*10187SKrishna.Elango@Sun.COM * Name the child 692*10187SKrishna.Elango@Sun.COM */ 693*10187SKrishna.Elango@Sun.COM if (pcieb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) { 694*10187SKrishna.Elango@Sun.COM result = DDI_FAILURE; 695*10187SKrishna.Elango@Sun.COM goto done; 696*10187SKrishna.Elango@Sun.COM } 697*10187SKrishna.Elango@Sun.COM ddi_set_name_addr(child, name); 698*10187SKrishna.Elango@Sun.COM 699*10187SKrishna.Elango@Sun.COM /* 700*10187SKrishna.Elango@Sun.COM * Pseudo nodes indicate a prototype node with per-instance 701*10187SKrishna.Elango@Sun.COM * properties to be merged into the real h/w device node. 702*10187SKrishna.Elango@Sun.COM * The interpretation of the unit-address is DD[,F] 703*10187SKrishna.Elango@Sun.COM * where DD is the device id and F is the function. 704*10187SKrishna.Elango@Sun.COM */ 705*10187SKrishna.Elango@Sun.COM if (ndi_dev_is_persistent_node(child) == 0) { 706*10187SKrishna.Elango@Sun.COM extern int pci_allow_pseudo_children; 707*10187SKrishna.Elango@Sun.COM 708*10187SKrishna.Elango@Sun.COM /* 709*10187SKrishna.Elango@Sun.COM * Try to merge the properties from this prototype 710*10187SKrishna.Elango@Sun.COM * node into real h/w nodes. 711*10187SKrishna.Elango@Sun.COM */ 712*10187SKrishna.Elango@Sun.COM if (ndi_merge_node(child, pcieb_name_child) != DDI_SUCCESS) { 713*10187SKrishna.Elango@Sun.COM /* 714*10187SKrishna.Elango@Sun.COM * Merged ok - return failure to remove the node. 715*10187SKrishna.Elango@Sun.COM */ 716*10187SKrishna.Elango@Sun.COM ddi_set_name_addr(child, NULL); 717*10187SKrishna.Elango@Sun.COM result = DDI_FAILURE; 718*10187SKrishna.Elango@Sun.COM goto done; 719*10187SKrishna.Elango@Sun.COM } 720*10187SKrishna.Elango@Sun.COM 721*10187SKrishna.Elango@Sun.COM /* workaround for ddivs to run under PCI-E */ 722*10187SKrishna.Elango@Sun.COM if (pci_allow_pseudo_children) { 723*10187SKrishna.Elango@Sun.COM result = DDI_SUCCESS; 724*10187SKrishna.Elango@Sun.COM goto done; 725*10187SKrishna.Elango@Sun.COM } 726*10187SKrishna.Elango@Sun.COM 727*10187SKrishna.Elango@Sun.COM /* 728*10187SKrishna.Elango@Sun.COM * The child was not merged into a h/w node, 729*10187SKrishna.Elango@Sun.COM * but there's not much we can do with it other 730*10187SKrishna.Elango@Sun.COM * than return failure to cause the node to be removed. 731*10187SKrishna.Elango@Sun.COM */ 732*10187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 733*10187SKrishna.Elango@Sun.COM ddi_driver_name(child), ddi_get_name_addr(child), 734*10187SKrishna.Elango@Sun.COM ddi_driver_name(child)); 735*10187SKrishna.Elango@Sun.COM ddi_set_name_addr(child, NULL); 736*10187SKrishna.Elango@Sun.COM result = DDI_NOT_WELL_FORMED; 737*10187SKrishna.Elango@Sun.COM goto done; 738*10187SKrishna.Elango@Sun.COM } 739*10187SKrishna.Elango@Sun.COM 740*10187SKrishna.Elango@Sun.COM /* platform specific initchild */ 741*10187SKrishna.Elango@Sun.COM pcieb_plat_initchild(child); 742*10187SKrishna.Elango@Sun.COM 743*10187SKrishna.Elango@Sun.COM if (pcie_pm_hold(pcieb->pcieb_dip) != DDI_SUCCESS) { 744*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, pcieb->pcieb_dip, 745*10187SKrishna.Elango@Sun.COM "INITCHILD: px_pm_hold failed\n"); 746*10187SKrishna.Elango@Sun.COM result = DDI_FAILURE; 747*10187SKrishna.Elango@Sun.COM goto done; 748*10187SKrishna.Elango@Sun.COM } 749*10187SKrishna.Elango@Sun.COM /* Any return from here must call pcie_pm_release */ 750*10187SKrishna.Elango@Sun.COM 751*10187SKrishna.Elango@Sun.COM /* 752*10187SKrishna.Elango@Sun.COM * If configuration registers were previously saved by 753*10187SKrishna.Elango@Sun.COM * child (before it entered D3), then let the child do the 754*10187SKrishna.Elango@Sun.COM * restore to set up the config regs as it'll first need to 755*10187SKrishna.Elango@Sun.COM * power the device out of D3. 756*10187SKrishna.Elango@Sun.COM */ 757*10187SKrishna.Elango@Sun.COM if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 758*10187SKrishna.Elango@Sun.COM "config-regs-saved-by-child") == 1) { 759*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child), 760*10187SKrishna.Elango@Sun.COM "INITCHILD: config regs to be restored by child" 761*10187SKrishna.Elango@Sun.COM " for %s@%s\n", ddi_node_name(child), 762*10187SKrishna.Elango@Sun.COM ddi_get_name_addr(child)); 763*10187SKrishna.Elango@Sun.COM 764*10187SKrishna.Elango@Sun.COM result = DDI_SUCCESS; 765*10187SKrishna.Elango@Sun.COM goto cleanup; 766*10187SKrishna.Elango@Sun.COM } 767*10187SKrishna.Elango@Sun.COM 768*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child), 769*10187SKrishna.Elango@Sun.COM "INITCHILD: config regs setup for %s@%s\n", 770*10187SKrishna.Elango@Sun.COM ddi_node_name(child), ddi_get_name_addr(child)); 771*10187SKrishna.Elango@Sun.COM 772*10187SKrishna.Elango@Sun.COM if (!pcie_init_bus(child) || pcie_initchild(child) != DDI_SUCCESS) { 773*10187SKrishna.Elango@Sun.COM result = DDI_FAILURE; 774*10187SKrishna.Elango@Sun.COM goto cleanup; 775*10187SKrishna.Elango@Sun.COM } 776*10187SKrishna.Elango@Sun.COM 777*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX 778*10187SKrishna.Elango@Sun.COM if (pcieb_init_plx_workarounds(pcieb, child) == DDI_FAILURE) { 779*10187SKrishna.Elango@Sun.COM result = DDI_FAILURE; 780*10187SKrishna.Elango@Sun.COM goto cleanup; 781*10187SKrishna.Elango@Sun.COM } 782*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 783*10187SKrishna.Elango@Sun.COM 784*10187SKrishna.Elango@Sun.COM result = DDI_SUCCESS; 785*10187SKrishna.Elango@Sun.COM cleanup: 786*10187SKrishna.Elango@Sun.COM pcie_pm_release(pcieb->pcieb_dip); 787*10187SKrishna.Elango@Sun.COM done: 788*10187SKrishna.Elango@Sun.COM return (result); 789*10187SKrishna.Elango@Sun.COM } 790*10187SKrishna.Elango@Sun.COM 791*10187SKrishna.Elango@Sun.COM static void 792*10187SKrishna.Elango@Sun.COM pcieb_uninitchild(dev_info_t *dip) 793*10187SKrishna.Elango@Sun.COM { 794*10187SKrishna.Elango@Sun.COM 795*10187SKrishna.Elango@Sun.COM pcie_uninitchild(dip); 796*10187SKrishna.Elango@Sun.COM 797*10187SKrishna.Elango@Sun.COM pcieb_plat_uninitchild(dip); 798*10187SKrishna.Elango@Sun.COM 799*10187SKrishna.Elango@Sun.COM ddi_set_name_addr(dip, NULL); 800*10187SKrishna.Elango@Sun.COM 801*10187SKrishna.Elango@Sun.COM /* 802*10187SKrishna.Elango@Sun.COM * Strip the node to properly convert it back to prototype form 803*10187SKrishna.Elango@Sun.COM */ 804*10187SKrishna.Elango@Sun.COM ddi_remove_minor_node(dip, NULL); 805*10187SKrishna.Elango@Sun.COM 806*10187SKrishna.Elango@Sun.COM ddi_prop_remove_all(dip); 807*10187SKrishna.Elango@Sun.COM } 808*10187SKrishna.Elango@Sun.COM 809*10187SKrishna.Elango@Sun.COM static boolean_t 810*10187SKrishna.Elango@Sun.COM pcieb_is_pcie_device_type(dev_info_t *dip) 811*10187SKrishna.Elango@Sun.COM { 812*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 813*10187SKrishna.Elango@Sun.COM 814*10187SKrishna.Elango@Sun.COM if (PCIE_IS_SW(bus_p) || PCIE_IS_RP(bus_p) || PCIE_IS_PCI2PCIE(bus_p)) 815*10187SKrishna.Elango@Sun.COM return (B_TRUE); 816*10187SKrishna.Elango@Sun.COM 817*10187SKrishna.Elango@Sun.COM return (B_FALSE); 818*10187SKrishna.Elango@Sun.COM } 819*10187SKrishna.Elango@Sun.COM 820*10187SKrishna.Elango@Sun.COM static int 821*10187SKrishna.Elango@Sun.COM pcieb_intr_attach(pcieb_devstate_t *pcieb) 822*10187SKrishna.Elango@Sun.COM { 823*10187SKrishna.Elango@Sun.COM int intr_types; 824*10187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb->pcieb_dip; 825*10187SKrishna.Elango@Sun.COM 826*10187SKrishna.Elango@Sun.COM /* Allow platform specific code to do any initialization first */ 827*10187SKrishna.Elango@Sun.COM pcieb_plat_intr_attach(pcieb); 828*10187SKrishna.Elango@Sun.COM 829*10187SKrishna.Elango@Sun.COM /* 830*10187SKrishna.Elango@Sun.COM * Initialize interrupt handlers. 831*10187SKrishna.Elango@Sun.COM * If both MSI and FIXED are supported, try to attach MSI first. 832*10187SKrishna.Elango@Sun.COM * If MSI fails for any reason, then try FIXED, but only allow one 833*10187SKrishna.Elango@Sun.COM * type to be attached. 834*10187SKrishna.Elango@Sun.COM */ 835*10187SKrishna.Elango@Sun.COM if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) { 836*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_supported_types" 837*10187SKrishna.Elango@Sun.COM " failed\n"); 838*10187SKrishna.Elango@Sun.COM goto FAIL; 839*10187SKrishna.Elango@Sun.COM } 840*10187SKrishna.Elango@Sun.COM 841*10187SKrishna.Elango@Sun.COM if ((intr_types & DDI_INTR_TYPE_MSI) && 842*10187SKrishna.Elango@Sun.COM (pcieb_msi_supported(dip) == DDI_SUCCESS)) { 843*10187SKrishna.Elango@Sun.COM if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_MSI) == DDI_SUCCESS) 844*10187SKrishna.Elango@Sun.COM intr_types = DDI_INTR_TYPE_MSI; 845*10187SKrishna.Elango@Sun.COM else { 846*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "Unable to attach MSI" 847*10187SKrishna.Elango@Sun.COM " handler\n"); 848*10187SKrishna.Elango@Sun.COM } 849*10187SKrishna.Elango@Sun.COM } 850*10187SKrishna.Elango@Sun.COM 851*10187SKrishna.Elango@Sun.COM if (intr_types != DDI_INTR_TYPE_MSI) { 852*10187SKrishna.Elango@Sun.COM /* 853*10187SKrishna.Elango@Sun.COM * MSIs are not supported or MSI initialization failed. For Root 854*10187SKrishna.Elango@Sun.COM * Ports mark this so error handling might try to fallback to 855*10187SKrishna.Elango@Sun.COM * some other mechanism if available (machinecheck etc.). 856*10187SKrishna.Elango@Sun.COM */ 857*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(PCIE_DIP2UPBUS(dip))) 858*10187SKrishna.Elango@Sun.COM pcieb->pcieb_no_aer_msi = B_TRUE; 859*10187SKrishna.Elango@Sun.COM } 860*10187SKrishna.Elango@Sun.COM 861*10187SKrishna.Elango@Sun.COM if (intr_types & DDI_INTR_TYPE_FIXED) { 862*10187SKrishna.Elango@Sun.COM if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_FIXED) != 863*10187SKrishna.Elango@Sun.COM DDI_SUCCESS) { 864*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, 865*10187SKrishna.Elango@Sun.COM "Unable to attach INTx handler\n"); 866*10187SKrishna.Elango@Sun.COM goto FAIL; 867*10187SKrishna.Elango@Sun.COM } 868*10187SKrishna.Elango@Sun.COM } 869*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 870*10187SKrishna.Elango@Sun.COM 871*10187SKrishna.Elango@Sun.COM FAIL: 872*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 873*10187SKrishna.Elango@Sun.COM } 874*10187SKrishna.Elango@Sun.COM 875*10187SKrishna.Elango@Sun.COM /* 876*10187SKrishna.Elango@Sun.COM * This function initializes internally generated interrupts only. 877*10187SKrishna.Elango@Sun.COM * It does not affect any interrupts generated by downstream devices 878*10187SKrishna.Elango@Sun.COM * or the forwarding of them. 879*10187SKrishna.Elango@Sun.COM * 880*10187SKrishna.Elango@Sun.COM * Enable Device Specific Interrupts or Hotplug features here. 881*10187SKrishna.Elango@Sun.COM * Enabling features may change how many interrupts are requested 882*10187SKrishna.Elango@Sun.COM * by the device. If features are not enabled first, the 883*10187SKrishna.Elango@Sun.COM * device might not ask for any interrupts. 884*10187SKrishna.Elango@Sun.COM */ 885*10187SKrishna.Elango@Sun.COM static int 886*10187SKrishna.Elango@Sun.COM pcieb_intr_init(pcieb_devstate_t *pcieb, int intr_type) 887*10187SKrishna.Elango@Sun.COM { 888*10187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb->pcieb_dip; 889*10187SKrishna.Elango@Sun.COM int nintrs, request, count, x; 890*10187SKrishna.Elango@Sun.COM int intr_cap = 0; 891*10187SKrishna.Elango@Sun.COM int inum = 0; 892*10187SKrishna.Elango@Sun.COM int ret, hp_msi_off; 893*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 894*10187SKrishna.Elango@Sun.COM uint16_t vendorid = bus_p->bus_dev_ven_id & 0xFFFF; 895*10187SKrishna.Elango@Sun.COM boolean_t is_hp = B_FALSE; 896*10187SKrishna.Elango@Sun.COM boolean_t is_pme = B_FALSE; 897*10187SKrishna.Elango@Sun.COM 898*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "pcieb_intr_init: Attaching %s handler\n", 899*10187SKrishna.Elango@Sun.COM (intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx"); 900*10187SKrishna.Elango@Sun.COM 901*10187SKrishna.Elango@Sun.COM request = 0; 902*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_hotplug_capable) { 903*10187SKrishna.Elango@Sun.COM request++; 904*10187SKrishna.Elango@Sun.COM is_hp = B_TRUE; 905*10187SKrishna.Elango@Sun.COM } 906*10187SKrishna.Elango@Sun.COM 907*10187SKrishna.Elango@Sun.COM /* 908*10187SKrishna.Elango@Sun.COM * Hotplug and PME share the same MSI vector. If hotplug is not 909*10187SKrishna.Elango@Sun.COM * supported check if MSI is needed for PME. 910*10187SKrishna.Elango@Sun.COM */ 911*10187SKrishna.Elango@Sun.COM if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p) && 912*10187SKrishna.Elango@Sun.COM (vendorid == NVIDIA_VENDOR_ID)) { 913*10187SKrishna.Elango@Sun.COM is_pme = B_TRUE; 914*10187SKrishna.Elango@Sun.COM if (!is_hp) 915*10187SKrishna.Elango@Sun.COM request++; 916*10187SKrishna.Elango@Sun.COM } 917*10187SKrishna.Elango@Sun.COM 918*10187SKrishna.Elango@Sun.COM /* 919*10187SKrishna.Elango@Sun.COM * Setup MSI if this device is a Rootport and has AER. Currently no 920*10187SKrishna.Elango@Sun.COM * SPARC Root Port supports fabric errors being reported through it. 921*10187SKrishna.Elango@Sun.COM */ 922*10187SKrishna.Elango@Sun.COM if (intr_type == DDI_INTR_TYPE_MSI) { 923*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p)) 924*10187SKrishna.Elango@Sun.COM request++; 925*10187SKrishna.Elango@Sun.COM } 926*10187SKrishna.Elango@Sun.COM 927*10187SKrishna.Elango@Sun.COM if (request == 0) 928*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 929*10187SKrishna.Elango@Sun.COM 930*10187SKrishna.Elango@Sun.COM /* 931*10187SKrishna.Elango@Sun.COM * Get number of supported interrupts. 932*10187SKrishna.Elango@Sun.COM * 933*10187SKrishna.Elango@Sun.COM * Several Bridges/Switches will not have this property set, resulting 934*10187SKrishna.Elango@Sun.COM * in a FAILURE, if the device is not configured in a way that 935*10187SKrishna.Elango@Sun.COM * interrupts are needed. (eg. hotplugging) 936*10187SKrishna.Elango@Sun.COM */ 937*10187SKrishna.Elango@Sun.COM ret = ddi_intr_get_nintrs(dip, intr_type, &nintrs); 938*10187SKrishna.Elango@Sun.COM if ((ret != DDI_SUCCESS) || (nintrs == 0)) { 939*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_nintrs ret:%d" 940*10187SKrishna.Elango@Sun.COM " req:%d\n", ret, nintrs); 941*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 942*10187SKrishna.Elango@Sun.COM } 943*10187SKrishna.Elango@Sun.COM 944*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0x%x: ddi_intr_get_nintrs: nintrs %d", 945*10187SKrishna.Elango@Sun.COM " request %d\n", bus_p->bus_bdf, nintrs, request); 946*10187SKrishna.Elango@Sun.COM 947*10187SKrishna.Elango@Sun.COM if (request > nintrs) 948*10187SKrishna.Elango@Sun.COM request = nintrs; 949*10187SKrishna.Elango@Sun.COM 950*10187SKrishna.Elango@Sun.COM /* Allocate an array of interrupt handlers */ 951*10187SKrishna.Elango@Sun.COM pcieb->pcieb_htable_size = sizeof (ddi_intr_handle_t) * request; 952*10187SKrishna.Elango@Sun.COM pcieb->pcieb_htable = kmem_zalloc(pcieb->pcieb_htable_size, 953*10187SKrishna.Elango@Sun.COM KM_SLEEP); 954*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags |= PCIEB_INIT_HTABLE; 955*10187SKrishna.Elango@Sun.COM 956*10187SKrishna.Elango@Sun.COM ret = ddi_intr_alloc(dip, pcieb->pcieb_htable, intr_type, inum, 957*10187SKrishna.Elango@Sun.COM request, &count, DDI_INTR_ALLOC_NORMAL); 958*10187SKrishna.Elango@Sun.COM if ((ret != DDI_SUCCESS) || (count == 0)) { 959*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_alloc() ret: %d ask: %d" 960*10187SKrishna.Elango@Sun.COM " actual: %d\n", ret, request, count); 961*10187SKrishna.Elango@Sun.COM goto FAIL; 962*10187SKrishna.Elango@Sun.COM } 963*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags |= PCIEB_INIT_ALLOC; 964*10187SKrishna.Elango@Sun.COM 965*10187SKrishna.Elango@Sun.COM /* Save the actual number of interrupts allocated */ 966*10187SKrishna.Elango@Sun.COM pcieb->pcieb_intr_count = count; 967*10187SKrishna.Elango@Sun.COM if (count < request) { 968*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0%x: Requested Intr: %d" 969*10187SKrishna.Elango@Sun.COM " Received: %d\n", bus_p->bus_bdf, request, count); 970*10187SKrishna.Elango@Sun.COM } 971*10187SKrishna.Elango@Sun.COM 972*10187SKrishna.Elango@Sun.COM /* 973*10187SKrishna.Elango@Sun.COM * NVidia (MCP55 and other) chipsets have a errata that if the number 974*10187SKrishna.Elango@Sun.COM * of requested MSI intrs is not allocated we have to fall back to INTx. 975*10187SKrishna.Elango@Sun.COM */ 976*10187SKrishna.Elango@Sun.COM if (intr_type == DDI_INTR_TYPE_MSI) { 977*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p) && (vendorid == NVIDIA_VENDOR_ID)) { 978*10187SKrishna.Elango@Sun.COM if (request != count) 979*10187SKrishna.Elango@Sun.COM goto FAIL; 980*10187SKrishna.Elango@Sun.COM } 981*10187SKrishna.Elango@Sun.COM } 982*10187SKrishna.Elango@Sun.COM 983*10187SKrishna.Elango@Sun.COM /* Get interrupt priority */ 984*10187SKrishna.Elango@Sun.COM ret = ddi_intr_get_pri(pcieb->pcieb_htable[0], 985*10187SKrishna.Elango@Sun.COM &pcieb->pcieb_intr_priority); 986*10187SKrishna.Elango@Sun.COM if (ret != DDI_SUCCESS) { 987*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_pri() ret: %d\n", 988*10187SKrishna.Elango@Sun.COM ret); 989*10187SKrishna.Elango@Sun.COM goto FAIL; 990*10187SKrishna.Elango@Sun.COM } 991*10187SKrishna.Elango@Sun.COM 992*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_intr_priority >= LOCK_LEVEL) { 993*10187SKrishna.Elango@Sun.COM pcieb->pcieb_intr_priority = LOCK_LEVEL - 1; 994*10187SKrishna.Elango@Sun.COM ret = ddi_intr_set_pri(pcieb->pcieb_htable[0], 995*10187SKrishna.Elango@Sun.COM pcieb->pcieb_intr_priority); 996*10187SKrishna.Elango@Sun.COM if (ret != DDI_SUCCESS) { 997*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_set_pri() ret:" 998*10187SKrishna.Elango@Sun.COM " %d\n", ret); 999*10187SKrishna.Elango@Sun.COM 1000*10187SKrishna.Elango@Sun.COM goto FAIL; 1001*10187SKrishna.Elango@Sun.COM } 1002*10187SKrishna.Elango@Sun.COM } 1003*10187SKrishna.Elango@Sun.COM 1004*10187SKrishna.Elango@Sun.COM mutex_init(&pcieb->pcieb_intr_mutex, NULL, MUTEX_DRIVER, NULL); 1005*10187SKrishna.Elango@Sun.COM 1006*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags |= PCIEB_INIT_MUTEX; 1007*10187SKrishna.Elango@Sun.COM 1008*10187SKrishna.Elango@Sun.COM for (count = 0; count < pcieb->pcieb_intr_count; count++) { 1009*10187SKrishna.Elango@Sun.COM ret = ddi_intr_add_handler(pcieb->pcieb_htable[count], 1010*10187SKrishna.Elango@Sun.COM pcieb_intr_handler, (caddr_t)pcieb, 1011*10187SKrishna.Elango@Sun.COM (caddr_t)(uintptr_t)(inum + count)); 1012*10187SKrishna.Elango@Sun.COM 1013*10187SKrishna.Elango@Sun.COM if (ret != DDI_SUCCESS) { 1014*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "Cannot add " 1015*10187SKrishna.Elango@Sun.COM "interrupt(%d)\n", ret); 1016*10187SKrishna.Elango@Sun.COM break; 1017*10187SKrishna.Elango@Sun.COM } 1018*10187SKrishna.Elango@Sun.COM } 1019*10187SKrishna.Elango@Sun.COM 1020*10187SKrishna.Elango@Sun.COM /* If unsucessful, remove the added handlers */ 1021*10187SKrishna.Elango@Sun.COM if (ret != DDI_SUCCESS) { 1022*10187SKrishna.Elango@Sun.COM for (x = 0; x < count; x++) { 1023*10187SKrishna.Elango@Sun.COM (void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]); 1024*10187SKrishna.Elango@Sun.COM } 1025*10187SKrishna.Elango@Sun.COM goto FAIL; 1026*10187SKrishna.Elango@Sun.COM } 1027*10187SKrishna.Elango@Sun.COM 1028*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags |= PCIEB_INIT_HANDLER; 1029*10187SKrishna.Elango@Sun.COM 1030*10187SKrishna.Elango@Sun.COM (void) ddi_intr_get_cap(pcieb->pcieb_htable[0], &intr_cap); 1031*10187SKrishna.Elango@Sun.COM 1032*10187SKrishna.Elango@Sun.COM /* 1033*10187SKrishna.Elango@Sun.COM * Get this intr lock because we are not quite ready to handle 1034*10187SKrishna.Elango@Sun.COM * interrupts immediately after enabling it. The MSI multi register 1035*10187SKrishna.Elango@Sun.COM * gets programmed in ddi_intr_enable after which we need to get the 1036*10187SKrishna.Elango@Sun.COM * MSI offsets for Hotplug/AER. 1037*10187SKrishna.Elango@Sun.COM */ 1038*10187SKrishna.Elango@Sun.COM mutex_enter(&pcieb->pcieb_intr_mutex); 1039*10187SKrishna.Elango@Sun.COM 1040*10187SKrishna.Elango@Sun.COM if (intr_cap & DDI_INTR_FLAG_BLOCK) { 1041*10187SKrishna.Elango@Sun.COM (void) ddi_intr_block_enable(pcieb->pcieb_htable, 1042*10187SKrishna.Elango@Sun.COM pcieb->pcieb_intr_count); 1043*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags |= PCIEB_INIT_BLOCK; 1044*10187SKrishna.Elango@Sun.COM } else { 1045*10187SKrishna.Elango@Sun.COM for (count = 0; count < pcieb->pcieb_intr_count; count++) { 1046*10187SKrishna.Elango@Sun.COM (void) ddi_intr_enable(pcieb->pcieb_htable[count]); 1047*10187SKrishna.Elango@Sun.COM } 1048*10187SKrishna.Elango@Sun.COM } 1049*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags |= PCIEB_INIT_ENABLE; 1050*10187SKrishna.Elango@Sun.COM 1051*10187SKrishna.Elango@Sun.COM /* Save the interrupt type */ 1052*10187SKrishna.Elango@Sun.COM pcieb->pcieb_intr_type = intr_type; 1053*10187SKrishna.Elango@Sun.COM 1054*10187SKrishna.Elango@Sun.COM /* Get the MSI offset for hotplug/PME from the PCIe cap reg */ 1055*10187SKrishna.Elango@Sun.COM if (intr_type == DDI_INTR_TYPE_MSI) { 1056*10187SKrishna.Elango@Sun.COM hp_msi_off = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL, 1057*10187SKrishna.Elango@Sun.COM bus_p->bus_pcie_off, PCIE_PCIECAP) & 1058*10187SKrishna.Elango@Sun.COM PCIE_PCIECAP_INT_MSG_NUM; 1059*10187SKrishna.Elango@Sun.COM 1060*10187SKrishna.Elango@Sun.COM if (hp_msi_off >= count) { 1061*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in PCIe " 1062*10187SKrishna.Elango@Sun.COM "cap > max allocated %d\n", hp_msi_off, count); 1063*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb->pcieb_intr_mutex); 1064*10187SKrishna.Elango@Sun.COM goto FAIL; 1065*10187SKrishna.Elango@Sun.COM } 1066*10187SKrishna.Elango@Sun.COM 1067*10187SKrishna.Elango@Sun.COM if (is_hp) 1068*10187SKrishna.Elango@Sun.COM pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_HP; 1069*10187SKrishna.Elango@Sun.COM 1070*10187SKrishna.Elango@Sun.COM if (is_pme) 1071*10187SKrishna.Elango@Sun.COM pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_PME; 1072*10187SKrishna.Elango@Sun.COM } else { 1073*10187SKrishna.Elango@Sun.COM /* INTx handles only Hotplug interrupts */ 1074*10187SKrishna.Elango@Sun.COM if (is_hp) 1075*10187SKrishna.Elango@Sun.COM pcieb->pcieb_isr_tab[0] |= PCIEB_INTR_SRC_HP; 1076*10187SKrishna.Elango@Sun.COM } 1077*10187SKrishna.Elango@Sun.COM 1078*10187SKrishna.Elango@Sun.COM 1079*10187SKrishna.Elango@Sun.COM /* 1080*10187SKrishna.Elango@Sun.COM * Get the MSI offset for errors from the AER Root Error status 1081*10187SKrishna.Elango@Sun.COM * register. 1082*10187SKrishna.Elango@Sun.COM */ 1083*10187SKrishna.Elango@Sun.COM if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p)) { 1084*10187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(bus_p)) { 1085*10187SKrishna.Elango@Sun.COM int aer_msi_off; 1086*10187SKrishna.Elango@Sun.COM aer_msi_off = (PCI_XCAP_GET32(bus_p->bus_cfg_hdl, NULL, 1087*10187SKrishna.Elango@Sun.COM bus_p->bus_aer_off, PCIE_AER_RE_STS) >> 1088*10187SKrishna.Elango@Sun.COM PCIE_AER_RE_STS_MSG_NUM_SHIFT) & 1089*10187SKrishna.Elango@Sun.COM PCIE_AER_RE_STS_MSG_NUM_MASK; 1090*10187SKrishna.Elango@Sun.COM 1091*10187SKrishna.Elango@Sun.COM if (aer_msi_off >= count) { 1092*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in" 1093*10187SKrishna.Elango@Sun.COM " AER cap > max allocated %d\n", 1094*10187SKrishna.Elango@Sun.COM aer_msi_off, count); 1095*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb->pcieb_intr_mutex); 1096*10187SKrishna.Elango@Sun.COM goto FAIL; 1097*10187SKrishna.Elango@Sun.COM } 1098*10187SKrishna.Elango@Sun.COM pcieb->pcieb_isr_tab[aer_msi_off] |= PCIEB_INTR_SRC_AER; 1099*10187SKrishna.Elango@Sun.COM } else { 1100*10187SKrishna.Elango@Sun.COM /* 1101*10187SKrishna.Elango@Sun.COM * This RP does not have AER. Fallback to the 1102*10187SKrishna.Elango@Sun.COM * SERR+Machinecheck approach if available. 1103*10187SKrishna.Elango@Sun.COM */ 1104*10187SKrishna.Elango@Sun.COM pcieb->pcieb_no_aer_msi = B_TRUE; 1105*10187SKrishna.Elango@Sun.COM } 1106*10187SKrishna.Elango@Sun.COM } 1107*10187SKrishna.Elango@Sun.COM 1108*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb->pcieb_intr_mutex); 1109*10187SKrishna.Elango@Sun.COM 1110*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1111*10187SKrishna.Elango@Sun.COM 1112*10187SKrishna.Elango@Sun.COM FAIL: 1113*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1114*10187SKrishna.Elango@Sun.COM } 1115*10187SKrishna.Elango@Sun.COM 1116*10187SKrishna.Elango@Sun.COM static void 1117*10187SKrishna.Elango@Sun.COM pcieb_intr_fini(pcieb_devstate_t *pcieb) 1118*10187SKrishna.Elango@Sun.COM { 1119*10187SKrishna.Elango@Sun.COM int x; 1120*10187SKrishna.Elango@Sun.COM int count = pcieb->pcieb_intr_count; 1121*10187SKrishna.Elango@Sun.COM int flags = pcieb->pcieb_init_flags; 1122*10187SKrishna.Elango@Sun.COM 1123*10187SKrishna.Elango@Sun.COM if ((flags & PCIEB_INIT_ENABLE) && 1124*10187SKrishna.Elango@Sun.COM (flags & PCIEB_INIT_BLOCK)) { 1125*10187SKrishna.Elango@Sun.COM (void) ddi_intr_block_disable(pcieb->pcieb_htable, count); 1126*10187SKrishna.Elango@Sun.COM flags &= ~(PCIEB_INIT_ENABLE | 1127*10187SKrishna.Elango@Sun.COM PCIEB_INIT_BLOCK); 1128*10187SKrishna.Elango@Sun.COM } 1129*10187SKrishna.Elango@Sun.COM 1130*10187SKrishna.Elango@Sun.COM if (flags & PCIEB_INIT_MUTEX) 1131*10187SKrishna.Elango@Sun.COM mutex_destroy(&pcieb->pcieb_intr_mutex); 1132*10187SKrishna.Elango@Sun.COM 1133*10187SKrishna.Elango@Sun.COM for (x = 0; x < count; x++) { 1134*10187SKrishna.Elango@Sun.COM if (flags & PCIEB_INIT_ENABLE) 1135*10187SKrishna.Elango@Sun.COM (void) ddi_intr_disable(pcieb->pcieb_htable[x]); 1136*10187SKrishna.Elango@Sun.COM 1137*10187SKrishna.Elango@Sun.COM if (flags & PCIEB_INIT_HANDLER) 1138*10187SKrishna.Elango@Sun.COM (void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]); 1139*10187SKrishna.Elango@Sun.COM 1140*10187SKrishna.Elango@Sun.COM if (flags & PCIEB_INIT_ALLOC) 1141*10187SKrishna.Elango@Sun.COM (void) ddi_intr_free(pcieb->pcieb_htable[x]); 1142*10187SKrishna.Elango@Sun.COM } 1143*10187SKrishna.Elango@Sun.COM 1144*10187SKrishna.Elango@Sun.COM flags &= ~(PCIEB_INIT_ENABLE | PCIEB_INIT_HANDLER | PCIEB_INIT_ALLOC | 1145*10187SKrishna.Elango@Sun.COM PCIEB_INIT_MUTEX); 1146*10187SKrishna.Elango@Sun.COM 1147*10187SKrishna.Elango@Sun.COM if (flags & PCIEB_INIT_HTABLE) 1148*10187SKrishna.Elango@Sun.COM kmem_free(pcieb->pcieb_htable, pcieb->pcieb_htable_size); 1149*10187SKrishna.Elango@Sun.COM 1150*10187SKrishna.Elango@Sun.COM flags &= ~PCIEB_INIT_HTABLE; 1151*10187SKrishna.Elango@Sun.COM 1152*10187SKrishna.Elango@Sun.COM pcieb->pcieb_init_flags &= flags; 1153*10187SKrishna.Elango@Sun.COM } 1154*10187SKrishna.Elango@Sun.COM 1155*10187SKrishna.Elango@Sun.COM /* 1156*10187SKrishna.Elango@Sun.COM * Checks if this device needs MSIs enabled or not. 1157*10187SKrishna.Elango@Sun.COM */ 1158*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 1159*10187SKrishna.Elango@Sun.COM static int 1160*10187SKrishna.Elango@Sun.COM pcieb_msi_supported(dev_info_t *dip) 1161*10187SKrishna.Elango@Sun.COM { 1162*10187SKrishna.Elango@Sun.COM return ((pcieb_enable_msi && pcieb_plat_msi_supported(dip)) ? 1163*10187SKrishna.Elango@Sun.COM DDI_SUCCESS: DDI_FAILURE); 1164*10187SKrishna.Elango@Sun.COM } 1165*10187SKrishna.Elango@Sun.COM 1166*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 1167*10187SKrishna.Elango@Sun.COM int 1168*10187SKrishna.Elango@Sun.COM pcieb_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap, 1169*10187SKrishna.Elango@Sun.COM ddi_iblock_cookie_t *ibc) 1170*10187SKrishna.Elango@Sun.COM { 1171*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, 1172*10187SKrishna.Elango@Sun.COM ddi_get_instance(dip)); 1173*10187SKrishna.Elango@Sun.COM 1174*10187SKrishna.Elango@Sun.COM ASSERT(ibc != NULL); 1175*10187SKrishna.Elango@Sun.COM *ibc = pcieb->pcieb_fm_ibc; 1176*10187SKrishna.Elango@Sun.COM 1177*10187SKrishna.Elango@Sun.COM return (DEVI(dip)->devi_fmhdl->fh_cap | DDI_FM_ACCCHK_CAPABLE | 1178*10187SKrishna.Elango@Sun.COM DDI_FM_DMACHK_CAPABLE); 1179*10187SKrishna.Elango@Sun.COM } 1180*10187SKrishna.Elango@Sun.COM 1181*10187SKrishna.Elango@Sun.COM static int 1182*10187SKrishna.Elango@Sun.COM pcieb_fm_init(pcieb_devstate_t *pcieb_p) 1183*10187SKrishna.Elango@Sun.COM { 1184*10187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb_p->pcieb_dip; 1185*10187SKrishna.Elango@Sun.COM int fm_cap = DDI_FM_EREPORT_CAPABLE; 1186*10187SKrishna.Elango@Sun.COM 1187*10187SKrishna.Elango@Sun.COM /* 1188*10187SKrishna.Elango@Sun.COM * Request our capability level and get our parents capability 1189*10187SKrishna.Elango@Sun.COM * and ibc. 1190*10187SKrishna.Elango@Sun.COM */ 1191*10187SKrishna.Elango@Sun.COM ddi_fm_init(dip, &fm_cap, &pcieb_p->pcieb_fm_ibc); 1192*10187SKrishna.Elango@Sun.COM 1193*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1194*10187SKrishna.Elango@Sun.COM } 1195*10187SKrishna.Elango@Sun.COM 1196*10187SKrishna.Elango@Sun.COM /* 1197*10187SKrishna.Elango@Sun.COM * Breakdown our FMA resources 1198*10187SKrishna.Elango@Sun.COM */ 1199*10187SKrishna.Elango@Sun.COM static void 1200*10187SKrishna.Elango@Sun.COM pcieb_fm_fini(pcieb_devstate_t *pcieb_p) 1201*10187SKrishna.Elango@Sun.COM { 1202*10187SKrishna.Elango@Sun.COM /* 1203*10187SKrishna.Elango@Sun.COM * Clean up allocated fm structures 1204*10187SKrishna.Elango@Sun.COM */ 1205*10187SKrishna.Elango@Sun.COM ddi_fm_fini(pcieb_p->pcieb_dip); 1206*10187SKrishna.Elango@Sun.COM } 1207*10187SKrishna.Elango@Sun.COM 1208*10187SKrishna.Elango@Sun.COM static int 1209*10187SKrishna.Elango@Sun.COM pcieb_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1210*10187SKrishna.Elango@Sun.COM { 1211*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb_p; 1212*10187SKrishna.Elango@Sun.COM minor_t minor = getminor(*devp); 1213*10187SKrishna.Elango@Sun.COM int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1214*10187SKrishna.Elango@Sun.COM 1215*10187SKrishna.Elango@Sun.COM /* 1216*10187SKrishna.Elango@Sun.COM * Make sure the open is for the right file type. 1217*10187SKrishna.Elango@Sun.COM */ 1218*10187SKrishna.Elango@Sun.COM if (otyp != OTYP_CHR) 1219*10187SKrishna.Elango@Sun.COM return (EINVAL); 1220*10187SKrishna.Elango@Sun.COM 1221*10187SKrishna.Elango@Sun.COM /* 1222*10187SKrishna.Elango@Sun.COM * Get the soft state structure for the device. 1223*10187SKrishna.Elango@Sun.COM */ 1224*10187SKrishna.Elango@Sun.COM pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state, 1225*10187SKrishna.Elango@Sun.COM instance); 1226*10187SKrishna.Elango@Sun.COM 1227*10187SKrishna.Elango@Sun.COM if (pcieb_p == NULL) 1228*10187SKrishna.Elango@Sun.COM return (ENXIO); 1229*10187SKrishna.Elango@Sun.COM 1230*10187SKrishna.Elango@Sun.COM if (pcieb_p->pcieb_hotplug_capable == B_TRUE) 1231*10187SKrishna.Elango@Sun.COM return ((pcihp_get_cb_ops())->cb_open(devp, flags, 1232*10187SKrishna.Elango@Sun.COM otyp, credp)); 1233*10187SKrishna.Elango@Sun.COM 1234*10187SKrishna.Elango@Sun.COM /* 1235*10187SKrishna.Elango@Sun.COM * Handle the open by tracking the device state. 1236*10187SKrishna.Elango@Sun.COM */ 1237*10187SKrishna.Elango@Sun.COM mutex_enter(&pcieb_p->pcieb_mutex); 1238*10187SKrishna.Elango@Sun.COM if (flags & FEXCL) { 1239*10187SKrishna.Elango@Sun.COM if (pcieb_p->pcieb_soft_state != PCIEB_SOFT_STATE_CLOSED) { 1240*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb_p->pcieb_mutex); 1241*10187SKrishna.Elango@Sun.COM return (EBUSY); 1242*10187SKrishna.Elango@Sun.COM } 1243*10187SKrishna.Elango@Sun.COM pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN_EXCL; 1244*10187SKrishna.Elango@Sun.COM } else { 1245*10187SKrishna.Elango@Sun.COM if (pcieb_p->pcieb_soft_state == PCIEB_SOFT_STATE_OPEN_EXCL) { 1246*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb_p->pcieb_mutex); 1247*10187SKrishna.Elango@Sun.COM return (EBUSY); 1248*10187SKrishna.Elango@Sun.COM } 1249*10187SKrishna.Elango@Sun.COM pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN; 1250*10187SKrishna.Elango@Sun.COM } 1251*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb_p->pcieb_mutex); 1252*10187SKrishna.Elango@Sun.COM return (0); 1253*10187SKrishna.Elango@Sun.COM } 1254*10187SKrishna.Elango@Sun.COM 1255*10187SKrishna.Elango@Sun.COM static int 1256*10187SKrishna.Elango@Sun.COM pcieb_close(dev_t dev, int flags, int otyp, cred_t *credp) 1257*10187SKrishna.Elango@Sun.COM { 1258*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb_p; 1259*10187SKrishna.Elango@Sun.COM minor_t minor = getminor(dev); 1260*10187SKrishna.Elango@Sun.COM int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1261*10187SKrishna.Elango@Sun.COM 1262*10187SKrishna.Elango@Sun.COM if (otyp != OTYP_CHR) 1263*10187SKrishna.Elango@Sun.COM return (EINVAL); 1264*10187SKrishna.Elango@Sun.COM 1265*10187SKrishna.Elango@Sun.COM pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state, 1266*10187SKrishna.Elango@Sun.COM instance); 1267*10187SKrishna.Elango@Sun.COM 1268*10187SKrishna.Elango@Sun.COM if (pcieb_p == NULL) 1269*10187SKrishna.Elango@Sun.COM return (ENXIO); 1270*10187SKrishna.Elango@Sun.COM 1271*10187SKrishna.Elango@Sun.COM if (pcieb_p->pcieb_hotplug_capable == B_TRUE) 1272*10187SKrishna.Elango@Sun.COM return ((pcihp_get_cb_ops())->cb_close(dev, flags, 1273*10187SKrishna.Elango@Sun.COM otyp, credp)); 1274*10187SKrishna.Elango@Sun.COM 1275*10187SKrishna.Elango@Sun.COM mutex_enter(&pcieb_p->pcieb_mutex); 1276*10187SKrishna.Elango@Sun.COM pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED; 1277*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb_p->pcieb_mutex); 1278*10187SKrishna.Elango@Sun.COM return (0); 1279*10187SKrishna.Elango@Sun.COM } 1280*10187SKrishna.Elango@Sun.COM 1281*10187SKrishna.Elango@Sun.COM static int 1282*10187SKrishna.Elango@Sun.COM pcieb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1283*10187SKrishna.Elango@Sun.COM int *rvalp) 1284*10187SKrishna.Elango@Sun.COM { 1285*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb_p; 1286*10187SKrishna.Elango@Sun.COM dev_info_t *self; 1287*10187SKrishna.Elango@Sun.COM struct devctl_iocdata *dcp; 1288*10187SKrishna.Elango@Sun.COM uint_t bus_state; 1289*10187SKrishna.Elango@Sun.COM int rv = 0; 1290*10187SKrishna.Elango@Sun.COM minor_t minor = getminor(dev); 1291*10187SKrishna.Elango@Sun.COM int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1292*10187SKrishna.Elango@Sun.COM 1293*10187SKrishna.Elango@Sun.COM pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state, 1294*10187SKrishna.Elango@Sun.COM instance); 1295*10187SKrishna.Elango@Sun.COM 1296*10187SKrishna.Elango@Sun.COM if (pcieb_p == NULL) 1297*10187SKrishna.Elango@Sun.COM return (ENXIO); 1298*10187SKrishna.Elango@Sun.COM 1299*10187SKrishna.Elango@Sun.COM self = pcieb_p->pcieb_dip; 1300*10187SKrishna.Elango@Sun.COM if (pcieb_p->pcieb_hotplug_capable == B_TRUE) { 1301*10187SKrishna.Elango@Sun.COM rv = ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, 1302*10187SKrishna.Elango@Sun.COM arg, mode, credp, rvalp)); 1303*10187SKrishna.Elango@Sun.COM 1304*10187SKrishna.Elango@Sun.COM pcieb_plat_ioctl_hotplug(self, rv, cmd); 1305*10187SKrishna.Elango@Sun.COM return (rv); 1306*10187SKrishna.Elango@Sun.COM } 1307*10187SKrishna.Elango@Sun.COM 1308*10187SKrishna.Elango@Sun.COM /* 1309*10187SKrishna.Elango@Sun.COM * We can use the generic implementation for these ioctls 1310*10187SKrishna.Elango@Sun.COM */ 1311*10187SKrishna.Elango@Sun.COM switch (cmd) { 1312*10187SKrishna.Elango@Sun.COM case DEVCTL_DEVICE_GETSTATE: 1313*10187SKrishna.Elango@Sun.COM case DEVCTL_DEVICE_ONLINE: 1314*10187SKrishna.Elango@Sun.COM case DEVCTL_DEVICE_OFFLINE: 1315*10187SKrishna.Elango@Sun.COM case DEVCTL_BUS_GETSTATE: 1316*10187SKrishna.Elango@Sun.COM return (ndi_devctl_ioctl(self, cmd, arg, mode, 0)); 1317*10187SKrishna.Elango@Sun.COM } 1318*10187SKrishna.Elango@Sun.COM 1319*10187SKrishna.Elango@Sun.COM /* 1320*10187SKrishna.Elango@Sun.COM * read devctl ioctl data 1321*10187SKrishna.Elango@Sun.COM */ 1322*10187SKrishna.Elango@Sun.COM if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 1323*10187SKrishna.Elango@Sun.COM return (EFAULT); 1324*10187SKrishna.Elango@Sun.COM 1325*10187SKrishna.Elango@Sun.COM switch (cmd) { 1326*10187SKrishna.Elango@Sun.COM 1327*10187SKrishna.Elango@Sun.COM case DEVCTL_DEVICE_RESET: 1328*10187SKrishna.Elango@Sun.COM rv = ENOTSUP; 1329*10187SKrishna.Elango@Sun.COM break; 1330*10187SKrishna.Elango@Sun.COM 1331*10187SKrishna.Elango@Sun.COM case DEVCTL_BUS_QUIESCE: 1332*10187SKrishna.Elango@Sun.COM if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1333*10187SKrishna.Elango@Sun.COM if (bus_state == BUS_QUIESCED) 1334*10187SKrishna.Elango@Sun.COM break; 1335*10187SKrishna.Elango@Sun.COM (void) ndi_set_bus_state(self, BUS_QUIESCED); 1336*10187SKrishna.Elango@Sun.COM break; 1337*10187SKrishna.Elango@Sun.COM 1338*10187SKrishna.Elango@Sun.COM case DEVCTL_BUS_UNQUIESCE: 1339*10187SKrishna.Elango@Sun.COM if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1340*10187SKrishna.Elango@Sun.COM if (bus_state == BUS_ACTIVE) 1341*10187SKrishna.Elango@Sun.COM break; 1342*10187SKrishna.Elango@Sun.COM (void) ndi_set_bus_state(self, BUS_ACTIVE); 1343*10187SKrishna.Elango@Sun.COM break; 1344*10187SKrishna.Elango@Sun.COM 1345*10187SKrishna.Elango@Sun.COM case DEVCTL_BUS_RESET: 1346*10187SKrishna.Elango@Sun.COM rv = ENOTSUP; 1347*10187SKrishna.Elango@Sun.COM break; 1348*10187SKrishna.Elango@Sun.COM 1349*10187SKrishna.Elango@Sun.COM case DEVCTL_BUS_RESETALL: 1350*10187SKrishna.Elango@Sun.COM rv = ENOTSUP; 1351*10187SKrishna.Elango@Sun.COM break; 1352*10187SKrishna.Elango@Sun.COM 1353*10187SKrishna.Elango@Sun.COM default: 1354*10187SKrishna.Elango@Sun.COM rv = ENOTTY; 1355*10187SKrishna.Elango@Sun.COM } 1356*10187SKrishna.Elango@Sun.COM 1357*10187SKrishna.Elango@Sun.COM ndi_dc_freehdl(dcp); 1358*10187SKrishna.Elango@Sun.COM return (rv); 1359*10187SKrishna.Elango@Sun.COM } 1360*10187SKrishna.Elango@Sun.COM 1361*10187SKrishna.Elango@Sun.COM static int 1362*10187SKrishna.Elango@Sun.COM pcieb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 1363*10187SKrishna.Elango@Sun.COM int flags, char *name, caddr_t valuep, int *lengthp) 1364*10187SKrishna.Elango@Sun.COM { 1365*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb_p; 1366*10187SKrishna.Elango@Sun.COM minor_t minor = getminor(dev); 1367*10187SKrishna.Elango@Sun.COM int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1368*10187SKrishna.Elango@Sun.COM 1369*10187SKrishna.Elango@Sun.COM pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state, 1370*10187SKrishna.Elango@Sun.COM instance); 1371*10187SKrishna.Elango@Sun.COM 1372*10187SKrishna.Elango@Sun.COM if (pcieb_p == NULL) 1373*10187SKrishna.Elango@Sun.COM return (ENXIO); 1374*10187SKrishna.Elango@Sun.COM 1375*10187SKrishna.Elango@Sun.COM if (pcieb_p->pcieb_hotplug_capable == B_TRUE) 1376*10187SKrishna.Elango@Sun.COM return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, 1377*10187SKrishna.Elango@Sun.COM flags, name, valuep, lengthp)); 1378*10187SKrishna.Elango@Sun.COM 1379*10187SKrishna.Elango@Sun.COM return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 1380*10187SKrishna.Elango@Sun.COM } 1381*10187SKrishna.Elango@Sun.COM 1382*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 1383*10187SKrishna.Elango@Sun.COM static int 1384*10187SKrishna.Elango@Sun.COM pcieb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1385*10187SKrishna.Elango@Sun.COM { 1386*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb_p; /* per pcieb state pointer */ 1387*10187SKrishna.Elango@Sun.COM minor_t minor = getminor((dev_t)arg); 1388*10187SKrishna.Elango@Sun.COM int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1389*10187SKrishna.Elango@Sun.COM 1390*10187SKrishna.Elango@Sun.COM pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state, 1391*10187SKrishna.Elango@Sun.COM instance); 1392*10187SKrishna.Elango@Sun.COM 1393*10187SKrishna.Elango@Sun.COM switch (infocmd) { 1394*10187SKrishna.Elango@Sun.COM default: 1395*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1396*10187SKrishna.Elango@Sun.COM 1397*10187SKrishna.Elango@Sun.COM case DDI_INFO_DEVT2INSTANCE: 1398*10187SKrishna.Elango@Sun.COM *result = (void *)(intptr_t)instance; 1399*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1400*10187SKrishna.Elango@Sun.COM 1401*10187SKrishna.Elango@Sun.COM case DDI_INFO_DEVT2DEVINFO: 1402*10187SKrishna.Elango@Sun.COM if (pcieb_p == NULL) 1403*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1404*10187SKrishna.Elango@Sun.COM *result = (void *)pcieb_p->pcieb_dip; 1405*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1406*10187SKrishna.Elango@Sun.COM } 1407*10187SKrishna.Elango@Sun.COM } 1408*10187SKrishna.Elango@Sun.COM 1409*10187SKrishna.Elango@Sun.COM /* 1410*10187SKrishna.Elango@Sun.COM * Common interrupt handler for hotplug, PME and errors. 1411*10187SKrishna.Elango@Sun.COM */ 1412*10187SKrishna.Elango@Sun.COM static uint_t 1413*10187SKrishna.Elango@Sun.COM pcieb_intr_handler(caddr_t arg1, caddr_t arg2) 1414*10187SKrishna.Elango@Sun.COM { 1415*10187SKrishna.Elango@Sun.COM pcieb_devstate_t *pcieb_p = (pcieb_devstate_t *)arg1; 1416*10187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb_p->pcieb_dip; 1417*10187SKrishna.Elango@Sun.COM ddi_fm_error_t derr; 1418*10187SKrishna.Elango@Sun.COM int sts = 0; 1419*10187SKrishna.Elango@Sun.COM int ret = DDI_INTR_UNCLAIMED; 1420*10187SKrishna.Elango@Sun.COM int isrc; 1421*10187SKrishna.Elango@Sun.COM 1422*10187SKrishna.Elango@Sun.COM if (!(pcieb_p->pcieb_init_flags & PCIEB_INIT_ENABLE)) 1423*10187SKrishna.Elango@Sun.COM goto FAIL; 1424*10187SKrishna.Elango@Sun.COM 1425*10187SKrishna.Elango@Sun.COM mutex_enter(&pcieb_p->pcieb_intr_mutex); 1426*10187SKrishna.Elango@Sun.COM isrc = pcieb_p->pcieb_isr_tab[(int)(uintptr_t)arg2]; 1427*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb_p->pcieb_intr_mutex); 1428*10187SKrishna.Elango@Sun.COM 1429*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_INTR, dip, "Received intr number %d\n", 1430*10187SKrishna.Elango@Sun.COM (int)(uintptr_t)arg2); 1431*10187SKrishna.Elango@Sun.COM 1432*10187SKrishna.Elango@Sun.COM if (isrc == PCIEB_INTR_SRC_UNKNOWN) 1433*10187SKrishna.Elango@Sun.COM goto FAIL; 1434*10187SKrishna.Elango@Sun.COM 1435*10187SKrishna.Elango@Sun.COM if (isrc & PCIEB_INTR_SRC_HP) { 1436*10187SKrishna.Elango@Sun.COM if (pcieb_p->pcieb_hpc_type == HPC_PCIE) 1437*10187SKrishna.Elango@Sun.COM ret = pciehpc_intr(dip); 1438*10187SKrishna.Elango@Sun.COM else if (pcieb_p->pcieb_hpc_type == HPC_SHPC) 1439*10187SKrishna.Elango@Sun.COM ret = pcishpc_intr(dip); 1440*10187SKrishna.Elango@Sun.COM } 1441*10187SKrishna.Elango@Sun.COM 1442*10187SKrishna.Elango@Sun.COM if (isrc & PCIEB_INTR_SRC_PME) 1443*10187SKrishna.Elango@Sun.COM ret = DDI_INTR_CLAIMED; 1444*10187SKrishna.Elango@Sun.COM 1445*10187SKrishna.Elango@Sun.COM /* AER Error */ 1446*10187SKrishna.Elango@Sun.COM if (isrc & PCIEB_INTR_SRC_AER) { 1447*10187SKrishna.Elango@Sun.COM /* 1448*10187SKrishna.Elango@Sun.COM * If MSI is shared with PME/hotplug then check Root Error 1449*10187SKrishna.Elango@Sun.COM * Status Reg before claiming it. For now it's ok since 1450*10187SKrishna.Elango@Sun.COM * we know we get 2 MSIs. 1451*10187SKrishna.Elango@Sun.COM */ 1452*10187SKrishna.Elango@Sun.COM ret = DDI_INTR_CLAIMED; 1453*10187SKrishna.Elango@Sun.COM bzero(&derr, sizeof (ddi_fm_error_t)); 1454*10187SKrishna.Elango@Sun.COM derr.fme_version = DDI_FME_VERSION; 1455*10187SKrishna.Elango@Sun.COM mutex_enter(&pcieb_p->pcieb_peek_poke_mutex); 1456*10187SKrishna.Elango@Sun.COM mutex_enter(&pcieb_p->pcieb_err_mutex); 1457*10187SKrishna.Elango@Sun.COM 1458*10187SKrishna.Elango@Sun.COM if ((DEVI(dip)->devi_fmhdl->fh_cap) & DDI_FM_EREPORT_CAPABLE) 1459*10187SKrishna.Elango@Sun.COM sts = pf_scan_fabric(dip, &derr, NULL); 1460*10187SKrishna.Elango@Sun.COM 1461*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb_p->pcieb_err_mutex); 1462*10187SKrishna.Elango@Sun.COM mutex_exit(&pcieb_p->pcieb_peek_poke_mutex); 1463*10187SKrishna.Elango@Sun.COM if (pcieb_die & sts) 1464*10187SKrishna.Elango@Sun.COM fm_panic("%s-%d: PCI(-X) Express Fatal Error. (0x%x)", 1465*10187SKrishna.Elango@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), sts); 1466*10187SKrishna.Elango@Sun.COM } 1467*10187SKrishna.Elango@Sun.COM FAIL: 1468*10187SKrishna.Elango@Sun.COM return (ret); 1469*10187SKrishna.Elango@Sun.COM } 1470*10187SKrishna.Elango@Sun.COM 1471*10187SKrishna.Elango@Sun.COM /* 1472*10187SKrishna.Elango@Sun.COM * Some PCI-X to PCI-E bridges do not support full 64-bit addressing on the 1473*10187SKrishna.Elango@Sun.COM * PCI-X side of the bridge. We build a special version of this driver for 1474*10187SKrishna.Elango@Sun.COM * those bridges, which uses PCIEB_ADDR_LIMIT_LO and/or PCIEB_ADDR_LIMIT_HI 1475*10187SKrishna.Elango@Sun.COM * to define the range of values which the chip can handle. The code below 1476*10187SKrishna.Elango@Sun.COM * then clamps the DMA address range supplied by the driver, preventing the 1477*10187SKrishna.Elango@Sun.COM * PCI-E nexus driver from allocating any memory the bridge can't deal 1478*10187SKrishna.Elango@Sun.COM * with. 1479*10187SKrishna.Elango@Sun.COM */ 1480*10187SKrishna.Elango@Sun.COM static int 1481*10187SKrishna.Elango@Sun.COM pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 1482*10187SKrishna.Elango@Sun.COM ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg, 1483*10187SKrishna.Elango@Sun.COM ddi_dma_handle_t *handlep) 1484*10187SKrishna.Elango@Sun.COM { 1485*10187SKrishna.Elango@Sun.COM int ret; 1486*10187SKrishna.Elango@Sun.COM #ifdef BCM_SW_WORKAROUNDS 1487*10187SKrishna.Elango@Sun.COM uint64_t lim; 1488*10187SKrishna.Elango@Sun.COM 1489*10187SKrishna.Elango@Sun.COM /* 1490*10187SKrishna.Elango@Sun.COM * If the leaf device's limits are outside than what the Broadcom 1491*10187SKrishna.Elango@Sun.COM * bridge can handle, we need to clip the values passed up the chain. 1492*10187SKrishna.Elango@Sun.COM */ 1493*10187SKrishna.Elango@Sun.COM lim = attr_p->dma_attr_addr_lo; 1494*10187SKrishna.Elango@Sun.COM attr_p->dma_attr_addr_lo = MAX(lim, PCIEB_ADDR_LIMIT_LO); 1495*10187SKrishna.Elango@Sun.COM 1496*10187SKrishna.Elango@Sun.COM lim = attr_p->dma_attr_addr_hi; 1497*10187SKrishna.Elango@Sun.COM attr_p->dma_attr_addr_hi = MIN(lim, PCIEB_ADDR_LIMIT_HI); 1498*10187SKrishna.Elango@Sun.COM 1499*10187SKrishna.Elango@Sun.COM #endif /* BCM_SW_WORKAROUNDS */ 1500*10187SKrishna.Elango@Sun.COM 1501*10187SKrishna.Elango@Sun.COM /* 1502*10187SKrishna.Elango@Sun.COM * This is a software workaround to fix the Broadcom 5714/5715 PCIe-PCI 1503*10187SKrishna.Elango@Sun.COM * bridge prefetch bug. Intercept the DMA alloc handle request and set 1504*10187SKrishna.Elango@Sun.COM * PX_DMAI_FLAGS_MAP_BUFZONE flag in the handle. If this flag is set, 1505*10187SKrishna.Elango@Sun.COM * the px nexus driver will allocate an extra page & make it valid one, 1506*10187SKrishna.Elango@Sun.COM * for any DVMA request that comes from any of the Broadcom bridge child 1507*10187SKrishna.Elango@Sun.COM * devices. 1508*10187SKrishna.Elango@Sun.COM */ 1509*10187SKrishna.Elango@Sun.COM if ((ret = ddi_dma_allochdl(dip, rdip, attr_p, waitfp, arg, 1510*10187SKrishna.Elango@Sun.COM handlep)) == DDI_SUCCESS) { 1511*10187SKrishna.Elango@Sun.COM ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*handlep; 1512*10187SKrishna.Elango@Sun.COM #ifdef BCM_SW_WORKAROUNDS 1513*10187SKrishna.Elango@Sun.COM mp->dmai_inuse |= PX_DMAI_FLAGS_MAP_BUFZONE; 1514*10187SKrishna.Elango@Sun.COM #endif /* BCM_SW_WORKAROUNDS */ 1515*10187SKrishna.Elango@Sun.COM /* 1516*10187SKrishna.Elango@Sun.COM * For a given rdip, update mp->dmai_bdf with the bdf value 1517*10187SKrishna.Elango@Sun.COM * of pcieb's immediate child or secondary bus-id of the 1518*10187SKrishna.Elango@Sun.COM * PCIe2PCI bridge. 1519*10187SKrishna.Elango@Sun.COM */ 1520*10187SKrishna.Elango@Sun.COM mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip); 1521*10187SKrishna.Elango@Sun.COM } 1522*10187SKrishna.Elango@Sun.COM 1523*10187SKrishna.Elango@Sun.COM return (ret); 1524*10187SKrishna.Elango@Sun.COM } 1525*10187SKrishna.Elango@Sun.COM 1526*10187SKrishna.Elango@Sun.COM /* 1527*10187SKrishna.Elango@Sun.COM * FDVMA feature is not supported for any child device of Broadcom 5714/5715 1528*10187SKrishna.Elango@Sun.COM * PCIe-PCI bridge due to prefetch bug. Return failure immediately, so that 1529*10187SKrishna.Elango@Sun.COM * these drivers will switch to regular DVMA path. 1530*10187SKrishna.Elango@Sun.COM */ 1531*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 1532*10187SKrishna.Elango@Sun.COM static int 1533*10187SKrishna.Elango@Sun.COM pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, 1534*10187SKrishna.Elango@Sun.COM enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp, 1535*10187SKrishna.Elango@Sun.COM uint_t cache_flags) 1536*10187SKrishna.Elango@Sun.COM { 1537*10187SKrishna.Elango@Sun.COM int ret; 1538*10187SKrishna.Elango@Sun.COM 1539*10187SKrishna.Elango@Sun.COM #ifdef BCM_SW_WORKAROUNDS 1540*10187SKrishna.Elango@Sun.COM if (cmd == DDI_DMA_RESERVE) 1541*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1542*10187SKrishna.Elango@Sun.COM #endif /* BCM_SW_WORKAROUNDS */ 1543*10187SKrishna.Elango@Sun.COM 1544*10187SKrishna.Elango@Sun.COM if (((ret = ddi_dma_mctl(dip, rdip, handle, cmd, offp, lenp, objp, 1545*10187SKrishna.Elango@Sun.COM cache_flags)) == DDI_SUCCESS) && (cmd == DDI_DMA_RESERVE)) { 1546*10187SKrishna.Elango@Sun.COM ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*objp; 1547*10187SKrishna.Elango@Sun.COM 1548*10187SKrishna.Elango@Sun.COM /* 1549*10187SKrishna.Elango@Sun.COM * For a given rdip, update mp->dmai_bdf with the bdf value 1550*10187SKrishna.Elango@Sun.COM * of pcieb's immediate child or secondary bus-id of the 1551*10187SKrishna.Elango@Sun.COM * PCIe2PCI bridge. 1552*10187SKrishna.Elango@Sun.COM */ 1553*10187SKrishna.Elango@Sun.COM mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip); 1554*10187SKrishna.Elango@Sun.COM } 1555*10187SKrishna.Elango@Sun.COM 1556*10187SKrishna.Elango@Sun.COM return (ret); 1557*10187SKrishna.Elango@Sun.COM } 1558*10187SKrishna.Elango@Sun.COM 1559*10187SKrishna.Elango@Sun.COM static int 1560*10187SKrishna.Elango@Sun.COM pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 1561*10187SKrishna.Elango@Sun.COM ddi_intr_handle_impl_t *hdlp, void *result) 1562*10187SKrishna.Elango@Sun.COM { 1563*10187SKrishna.Elango@Sun.COM return (pcieb_plat_intr_ops(dip, rdip, intr_op, hdlp, result)); 1564*10187SKrishna.Elango@Sun.COM 1565*10187SKrishna.Elango@Sun.COM } 1566*10187SKrishna.Elango@Sun.COM 1567*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 1568*10187SKrishna.Elango@Sun.COM static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle) 1569*10187SKrishna.Elango@Sun.COM { 1570*10187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 1571*10187SKrishna.Elango@Sun.COM 1572*10187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) != 1573*10187SKrishna.Elango@Sun.COM DDI_FAILURE) { 1574*10187SKrishna.Elango@Sun.COM uint16_t slotimpl = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 1575*10187SKrishna.Elango@Sun.COM PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL; 1576*10187SKrishna.Elango@Sun.COM if (slotimpl) 1577*10187SKrishna.Elango@Sun.COM if (PCI_CAP_GET32(config_handle, NULL, cap_ptr, 1578*10187SKrishna.Elango@Sun.COM PCIE_SLOTCAP) & PCIE_SLOTCAP_HP_CAPABLE) 1579*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1580*10187SKrishna.Elango@Sun.COM } 1581*10187SKrishna.Elango@Sun.COM 1582*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1583*10187SKrishna.Elango@Sun.COM } 1584*10187SKrishna.Elango@Sun.COM 1585*10187SKrishna.Elango@Sun.COM static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle) 1586*10187SKrishna.Elango@Sun.COM { 1587*10187SKrishna.Elango@Sun.COM return (pcieb_plat_pcishpc_probe(dip, config_handle)); 1588*10187SKrishna.Elango@Sun.COM } 1589*10187SKrishna.Elango@Sun.COM 1590*10187SKrishna.Elango@Sun.COM /* 1591*10187SKrishna.Elango@Sun.COM * Initialize hotplug framework if we are hotpluggable. 1592*10187SKrishna.Elango@Sun.COM * Sets flag in the soft state if Hot Plug is supported and initialized 1593*10187SKrishna.Elango@Sun.COM * properly. 1594*10187SKrishna.Elango@Sun.COM */ 1595*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 1596*10187SKrishna.Elango@Sun.COM static int 1597*10187SKrishna.Elango@Sun.COM pcieb_init_hotplug(pcieb_devstate_t *pcieb) 1598*10187SKrishna.Elango@Sun.COM { 1599*10187SKrishna.Elango@Sun.COM int rv = DDI_FAILURE; 1600*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip); 1601*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl; 1602*10187SKrishna.Elango@Sun.COM uint8_t dev_type = bus_p->bus_dev_type; 1603*10187SKrishna.Elango@Sun.COM 1604*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX 1605*10187SKrishna.Elango@Sun.COM uint16_t vid = bus_p->bus_dev_ven_id & 0xFFFF; 1606*10187SKrishna.Elango@Sun.COM uint16_t did = bus_p->bus_dev_ven_id >> 16; 1607*10187SKrishna.Elango@Sun.COM if ((vid == PXB_VENDOR_PLX) && (did == PXB_DEVICE_PLX_8532) && 1608*10187SKrishna.Elango@Sun.COM (bus_p->bus_rev_id <= PXB_DEVICE_PLX_AA_REV)) 1609*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1610*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 1611*10187SKrishna.Elango@Sun.COM 1612*10187SKrishna.Elango@Sun.COM if (((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) || 1613*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE) || 1614*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT)) && 1615*10187SKrishna.Elango@Sun.COM (pcieb_pciehpc_probe(pcieb->pcieb_dip, 1616*10187SKrishna.Elango@Sun.COM config_handle) == DDI_SUCCESS)) { 1617*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hpc_type = HPC_PCIE; 1618*10187SKrishna.Elango@Sun.COM } else if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) && 1619*10187SKrishna.Elango@Sun.COM (pcieb_pcishpc_probe(pcieb->pcieb_dip, 1620*10187SKrishna.Elango@Sun.COM config_handle) == DDI_SUCCESS)) { 1621*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hpc_type = HPC_SHPC; 1622*10187SKrishna.Elango@Sun.COM } else { 1623*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hpc_type = HPC_NONE; 1624*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1625*10187SKrishna.Elango@Sun.COM } 1626*10187SKrishna.Elango@Sun.COM 1627*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hotplug_capable = B_TRUE; 1628*10187SKrishna.Elango@Sun.COM 1629*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_hpc_type == HPC_PCIE) 1630*10187SKrishna.Elango@Sun.COM rv = pciehpc_init(pcieb->pcieb_dip, NULL); 1631*10187SKrishna.Elango@Sun.COM else if (pcieb->pcieb_hpc_type == HPC_SHPC) 1632*10187SKrishna.Elango@Sun.COM rv = pcishpc_init(pcieb->pcieb_dip); 1633*10187SKrishna.Elango@Sun.COM 1634*10187SKrishna.Elango@Sun.COM if (rv != DDI_SUCCESS) 1635*10187SKrishna.Elango@Sun.COM goto fail; 1636*10187SKrishna.Elango@Sun.COM 1637*10187SKrishna.Elango@Sun.COM if (pcihp_init(pcieb->pcieb_dip) != DDI_SUCCESS) { 1638*10187SKrishna.Elango@Sun.COM if (pcieb->pcieb_hpc_type == HPC_PCIE) 1639*10187SKrishna.Elango@Sun.COM (void) pciehpc_uninit(pcieb->pcieb_dip); 1640*10187SKrishna.Elango@Sun.COM else if (pcieb->pcieb_hpc_type == HPC_SHPC) 1641*10187SKrishna.Elango@Sun.COM (void) pcishpc_uninit(pcieb->pcieb_dip); 1642*10187SKrishna.Elango@Sun.COM 1643*10187SKrishna.Elango@Sun.COM goto fail; 1644*10187SKrishna.Elango@Sun.COM } 1645*10187SKrishna.Elango@Sun.COM 1646*10187SKrishna.Elango@Sun.COM (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip, 1647*10187SKrishna.Elango@Sun.COM "hotplug-capable"); 1648*10187SKrishna.Elango@Sun.COM 1649*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1650*10187SKrishna.Elango@Sun.COM 1651*10187SKrishna.Elango@Sun.COM fail: 1652*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hpc_type = HPC_NONE; 1653*10187SKrishna.Elango@Sun.COM pcieb->pcieb_hotplug_capable = B_FALSE; 1654*10187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "%s%d: Failed setting hotplug framework", 1655*10187SKrishna.Elango@Sun.COM ddi_driver_name(pcieb->pcieb_dip), 1656*10187SKrishna.Elango@Sun.COM ddi_get_instance(pcieb->pcieb_dip)); 1657*10187SKrishna.Elango@Sun.COM 1658*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1659*10187SKrishna.Elango@Sun.COM } 1660*10187SKrishna.Elango@Sun.COM 1661*10187SKrishna.Elango@Sun.COM /* 1662*10187SKrishna.Elango@Sun.COM * Power management related initialization specific to pcieb. 1663*10187SKrishna.Elango@Sun.COM * Called by pcieb_attach() 1664*10187SKrishna.Elango@Sun.COM */ 1665*10187SKrishna.Elango@Sun.COM static int 1666*10187SKrishna.Elango@Sun.COM pcieb_pwr_setup(dev_info_t *dip) 1667*10187SKrishna.Elango@Sun.COM { 1668*10187SKrishna.Elango@Sun.COM char *comp_array[5]; 1669*10187SKrishna.Elango@Sun.COM int i; 1670*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t conf_hdl; 1671*10187SKrishna.Elango@Sun.COM uint16_t pmcap, cap_ptr; 1672*10187SKrishna.Elango@Sun.COM pcie_pwr_t *pwr_p; 1673*10187SKrishna.Elango@Sun.COM 1674*10187SKrishna.Elango@Sun.COM /* Some platforms/devices may choose to disable PM */ 1675*10187SKrishna.Elango@Sun.COM if (pcieb_plat_pwr_disable(dip)) { 1676*10187SKrishna.Elango@Sun.COM (void) pcieb_pwr_disable(dip); 1677*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1678*10187SKrishna.Elango@Sun.COM } 1679*10187SKrishna.Elango@Sun.COM 1680*10187SKrishna.Elango@Sun.COM ASSERT(PCIE_PMINFO(dip)); 1681*10187SKrishna.Elango@Sun.COM pwr_p = PCIE_NEXUS_PMINFO(dip); 1682*10187SKrishna.Elango@Sun.COM ASSERT(pwr_p); 1683*10187SKrishna.Elango@Sun.COM 1684*10187SKrishna.Elango@Sun.COM /* Code taken from pci_pci driver */ 1685*10187SKrishna.Elango@Sun.COM if (pci_config_setup(dip, &pwr_p->pwr_conf_hdl) != DDI_SUCCESS) { 1686*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: pci_config_setup " 1687*10187SKrishna.Elango@Sun.COM "failed\n"); 1688*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1689*10187SKrishna.Elango@Sun.COM } 1690*10187SKrishna.Elango@Sun.COM conf_hdl = pwr_p->pwr_conf_hdl; 1691*10187SKrishna.Elango@Sun.COM 1692*10187SKrishna.Elango@Sun.COM /* 1693*10187SKrishna.Elango@Sun.COM * Walk the capabilities searching for a PM entry. 1694*10187SKrishna.Elango@Sun.COM */ 1695*10187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(conf_hdl, PCI_CAP_ID_PM, &cap_ptr)) == 1696*10187SKrishna.Elango@Sun.COM DDI_FAILURE) { 1697*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, dip, "switch/bridge does not support PM. " 1698*10187SKrishna.Elango@Sun.COM " PCI PM data structure not found in config header\n"); 1699*10187SKrishna.Elango@Sun.COM pci_config_teardown(&conf_hdl); 1700*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1701*10187SKrishna.Elango@Sun.COM } 1702*10187SKrishna.Elango@Sun.COM /* 1703*10187SKrishna.Elango@Sun.COM * Save offset to pmcsr for future references. 1704*10187SKrishna.Elango@Sun.COM */ 1705*10187SKrishna.Elango@Sun.COM pwr_p->pwr_pmcsr_offset = cap_ptr + PCI_PMCSR; 1706*10187SKrishna.Elango@Sun.COM pmcap = PCI_CAP_GET16(conf_hdl, NULL, cap_ptr, PCI_PMCAP); 1707*10187SKrishna.Elango@Sun.COM if (pmcap & PCI_PMCAP_D1) { 1708*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, dip, "D1 state supported\n"); 1709*10187SKrishna.Elango@Sun.COM pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D1; 1710*10187SKrishna.Elango@Sun.COM } 1711*10187SKrishna.Elango@Sun.COM if (pmcap & PCI_PMCAP_D2) { 1712*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, dip, "D2 state supported\n"); 1713*10187SKrishna.Elango@Sun.COM pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D2; 1714*10187SKrishna.Elango@Sun.COM } 1715*10187SKrishna.Elango@Sun.COM 1716*10187SKrishna.Elango@Sun.COM i = 0; 1717*10187SKrishna.Elango@Sun.COM comp_array[i++] = "NAME=PCIe switch/bridge PM"; 1718*10187SKrishna.Elango@Sun.COM comp_array[i++] = "0=Power Off (D3)"; 1719*10187SKrishna.Elango@Sun.COM if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D2) 1720*10187SKrishna.Elango@Sun.COM comp_array[i++] = "1=D2"; 1721*10187SKrishna.Elango@Sun.COM if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D1) 1722*10187SKrishna.Elango@Sun.COM comp_array[i++] = "2=D1"; 1723*10187SKrishna.Elango@Sun.COM comp_array[i++] = "3=Full Power D0"; 1724*10187SKrishna.Elango@Sun.COM 1725*10187SKrishna.Elango@Sun.COM /* 1726*10187SKrishna.Elango@Sun.COM * Create pm-components property, if it does not exist already. 1727*10187SKrishna.Elango@Sun.COM */ 1728*10187SKrishna.Elango@Sun.COM if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 1729*10187SKrishna.Elango@Sun.COM "pm-components", comp_array, i) != DDI_PROP_SUCCESS) { 1730*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, dip, "could not create pm-components " 1731*10187SKrishna.Elango@Sun.COM " prop\n"); 1732*10187SKrishna.Elango@Sun.COM pci_config_teardown(&conf_hdl); 1733*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 1734*10187SKrishna.Elango@Sun.COM } 1735*10187SKrishna.Elango@Sun.COM return (pcieb_pwr_init_and_raise(dip, pwr_p)); 1736*10187SKrishna.Elango@Sun.COM } 1737*10187SKrishna.Elango@Sun.COM 1738*10187SKrishna.Elango@Sun.COM /* 1739*10187SKrishna.Elango@Sun.COM * undo whatever is done in pcieb_pwr_setup. called by pcieb_detach() 1740*10187SKrishna.Elango@Sun.COM */ 1741*10187SKrishna.Elango@Sun.COM static void 1742*10187SKrishna.Elango@Sun.COM pcieb_pwr_teardown(dev_info_t *dip) 1743*10187SKrishna.Elango@Sun.COM { 1744*10187SKrishna.Elango@Sun.COM pcie_pwr_t *pwr_p; 1745*10187SKrishna.Elango@Sun.COM 1746*10187SKrishna.Elango@Sun.COM if (!PCIE_PMINFO(dip) || !(pwr_p = PCIE_NEXUS_PMINFO(dip))) 1747*10187SKrishna.Elango@Sun.COM return; 1748*10187SKrishna.Elango@Sun.COM 1749*10187SKrishna.Elango@Sun.COM (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components"); 1750*10187SKrishna.Elango@Sun.COM if (pwr_p->pwr_conf_hdl) 1751*10187SKrishna.Elango@Sun.COM pci_config_teardown(&pwr_p->pwr_conf_hdl); 1752*10187SKrishna.Elango@Sun.COM } 1753*10187SKrishna.Elango@Sun.COM 1754*10187SKrishna.Elango@Sun.COM /* 1755*10187SKrishna.Elango@Sun.COM * Initializes the power level and raise the power to D0, if it is 1756*10187SKrishna.Elango@Sun.COM * not at D0. 1757*10187SKrishna.Elango@Sun.COM */ 1758*10187SKrishna.Elango@Sun.COM static int 1759*10187SKrishna.Elango@Sun.COM pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p) 1760*10187SKrishna.Elango@Sun.COM { 1761*10187SKrishna.Elango@Sun.COM uint16_t pmcsr; 1762*10187SKrishna.Elango@Sun.COM int ret = DDI_SUCCESS; 1763*10187SKrishna.Elango@Sun.COM 1764*10187SKrishna.Elango@Sun.COM /* 1765*10187SKrishna.Elango@Sun.COM * Intialize our power level from PMCSR. The common code initializes 1766*10187SKrishna.Elango@Sun.COM * this to UNKNOWN. There is no guarantee that we will be at full 1767*10187SKrishna.Elango@Sun.COM * power at attach. If we are not at D0, raise the power. 1768*10187SKrishna.Elango@Sun.COM */ 1769*10187SKrishna.Elango@Sun.COM pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl, pwr_p->pwr_pmcsr_offset); 1770*10187SKrishna.Elango@Sun.COM pmcsr &= PCI_PMCSR_STATE_MASK; 1771*10187SKrishna.Elango@Sun.COM switch (pmcsr) { 1772*10187SKrishna.Elango@Sun.COM case PCI_PMCSR_D0: 1773*10187SKrishna.Elango@Sun.COM pwr_p->pwr_func_lvl = PM_LEVEL_D0; 1774*10187SKrishna.Elango@Sun.COM break; 1775*10187SKrishna.Elango@Sun.COM 1776*10187SKrishna.Elango@Sun.COM case PCI_PMCSR_D1: 1777*10187SKrishna.Elango@Sun.COM pwr_p->pwr_func_lvl = PM_LEVEL_D1; 1778*10187SKrishna.Elango@Sun.COM break; 1779*10187SKrishna.Elango@Sun.COM 1780*10187SKrishna.Elango@Sun.COM case PCI_PMCSR_D2: 1781*10187SKrishna.Elango@Sun.COM pwr_p->pwr_func_lvl = PM_LEVEL_D2; 1782*10187SKrishna.Elango@Sun.COM break; 1783*10187SKrishna.Elango@Sun.COM 1784*10187SKrishna.Elango@Sun.COM case PCI_PMCSR_D3HOT: 1785*10187SKrishna.Elango@Sun.COM pwr_p->pwr_func_lvl = PM_LEVEL_D3; 1786*10187SKrishna.Elango@Sun.COM break; 1787*10187SKrishna.Elango@Sun.COM 1788*10187SKrishna.Elango@Sun.COM default: 1789*10187SKrishna.Elango@Sun.COM break; 1790*10187SKrishna.Elango@Sun.COM } 1791*10187SKrishna.Elango@Sun.COM 1792*10187SKrishna.Elango@Sun.COM /* Raise the power to D0. */ 1793*10187SKrishna.Elango@Sun.COM if (pwr_p->pwr_func_lvl != PM_LEVEL_D0 && 1794*10187SKrishna.Elango@Sun.COM ((ret = pm_raise_power(dip, 0, PM_LEVEL_D0)) != DDI_SUCCESS)) { 1795*10187SKrishna.Elango@Sun.COM /* 1796*10187SKrishna.Elango@Sun.COM * Read PMCSR again. If it is at D0, ignore the return 1797*10187SKrishna.Elango@Sun.COM * value from pm_raise_power. 1798*10187SKrishna.Elango@Sun.COM */ 1799*10187SKrishna.Elango@Sun.COM pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl, 1800*10187SKrishna.Elango@Sun.COM pwr_p->pwr_pmcsr_offset); 1801*10187SKrishna.Elango@Sun.COM if ((pmcsr & PCI_PMCSR_STATE_MASK) == PCI_PMCSR_D0) 1802*10187SKrishna.Elango@Sun.COM ret = DDI_SUCCESS; 1803*10187SKrishna.Elango@Sun.COM else { 1804*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: could not " 1805*10187SKrishna.Elango@Sun.COM "raise power to D0 \n"); 1806*10187SKrishna.Elango@Sun.COM } 1807*10187SKrishna.Elango@Sun.COM } 1808*10187SKrishna.Elango@Sun.COM if (ret == DDI_SUCCESS) 1809*10187SKrishna.Elango@Sun.COM pwr_p->pwr_func_lvl = PM_LEVEL_D0; 1810*10187SKrishna.Elango@Sun.COM return (ret); 1811*10187SKrishna.Elango@Sun.COM } 1812*10187SKrishna.Elango@Sun.COM 1813*10187SKrishna.Elango@Sun.COM /* 1814*10187SKrishna.Elango@Sun.COM * Disable PM for x86 and PLX 8532 switch. 1815*10187SKrishna.Elango@Sun.COM * For PLX Transitioning one port on this switch to low power causes links 1816*10187SKrishna.Elango@Sun.COM * on other ports on the same station to die. Due to PLX erratum #34, we 1817*10187SKrishna.Elango@Sun.COM * can't allow the downstream device go to non-D0 state. 1818*10187SKrishna.Elango@Sun.COM */ 1819*10187SKrishna.Elango@Sun.COM static int 1820*10187SKrishna.Elango@Sun.COM pcieb_pwr_disable(dev_info_t *dip) 1821*10187SKrishna.Elango@Sun.COM { 1822*10187SKrishna.Elango@Sun.COM pcie_pwr_t *pwr_p; 1823*10187SKrishna.Elango@Sun.COM 1824*10187SKrishna.Elango@Sun.COM ASSERT(PCIE_PMINFO(dip)); 1825*10187SKrishna.Elango@Sun.COM pwr_p = PCIE_NEXUS_PMINFO(dip); 1826*10187SKrishna.Elango@Sun.COM ASSERT(pwr_p); 1827*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_disable: disabling PM\n"); 1828*10187SKrishna.Elango@Sun.COM pwr_p->pwr_func_lvl = PM_LEVEL_D0; 1829*10187SKrishna.Elango@Sun.COM pwr_p->pwr_flags = PCIE_NO_CHILD_PM; 1830*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 1831*10187SKrishna.Elango@Sun.COM } 1832*10187SKrishna.Elango@Sun.COM 1833*10187SKrishna.Elango@Sun.COM #ifdef DEBUG 1834*10187SKrishna.Elango@Sun.COM int pcieb_dbg_intr_print = 0; 1835*10187SKrishna.Elango@Sun.COM void 1836*10187SKrishna.Elango@Sun.COM pcieb_dbg(uint_t bit, dev_info_t *dip, char *fmt, ...) 1837*10187SKrishna.Elango@Sun.COM { 1838*10187SKrishna.Elango@Sun.COM va_list ap; 1839*10187SKrishna.Elango@Sun.COM 1840*10187SKrishna.Elango@Sun.COM if (!pcieb_dbg_print) 1841*10187SKrishna.Elango@Sun.COM return; 1842*10187SKrishna.Elango@Sun.COM 1843*10187SKrishna.Elango@Sun.COM if (dip) 1844*10187SKrishna.Elango@Sun.COM prom_printf("%s(%d): %s", ddi_driver_name(dip), 1845*10187SKrishna.Elango@Sun.COM ddi_get_instance(dip), pcieb_debug_sym[bit]); 1846*10187SKrishna.Elango@Sun.COM 1847*10187SKrishna.Elango@Sun.COM va_start(ap, fmt); 1848*10187SKrishna.Elango@Sun.COM if (servicing_interrupt()) { 1849*10187SKrishna.Elango@Sun.COM if (pcieb_dbg_intr_print) 1850*10187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 1851*10187SKrishna.Elango@Sun.COM } else { 1852*10187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 1853*10187SKrishna.Elango@Sun.COM } 1854*10187SKrishna.Elango@Sun.COM 1855*10187SKrishna.Elango@Sun.COM va_end(ap); 1856*10187SKrishna.Elango@Sun.COM } 1857*10187SKrishna.Elango@Sun.COM #endif 1858*10187SKrishna.Elango@Sun.COM 1859*10187SKrishna.Elango@Sun.COM static void 1860*10187SKrishna.Elango@Sun.COM pcieb_id_props(pcieb_devstate_t *pcieb) 1861*10187SKrishna.Elango@Sun.COM { 1862*10187SKrishna.Elango@Sun.COM uint64_t serialid = 0; /* 40b field of EUI-64 serial no. register */ 1863*10187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 1864*10187SKrishna.Elango@Sun.COM uint8_t fic = 0; /* 1 = first in chassis device */ 1865*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip); 1866*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl; 1867*10187SKrishna.Elango@Sun.COM 1868*10187SKrishna.Elango@Sun.COM /* 1869*10187SKrishna.Elango@Sun.COM * Identify first in chassis. In the special case of a Sun branded 1870*10187SKrishna.Elango@Sun.COM * PLX device, it obviously is first in chassis. Otherwise, in the 1871*10187SKrishna.Elango@Sun.COM * general case, look for an Expansion Slot Register and check its 1872*10187SKrishna.Elango@Sun.COM * first-in-chassis bit. 1873*10187SKrishna.Elango@Sun.COM */ 1874*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX 1875*10187SKrishna.Elango@Sun.COM uint16_t vendor_id = bus_p->bus_dev_ven_id & 0xFFFF; 1876*10187SKrishna.Elango@Sun.COM uint16_t device_id = bus_p->bus_dev_ven_id >> 16; 1877*10187SKrishna.Elango@Sun.COM if ((vendor_id == PXB_VENDOR_SUN) && 1878*10187SKrishna.Elango@Sun.COM ((device_id == PXB_DEVICE_PLX_PCIX) || 1879*10187SKrishna.Elango@Sun.COM (device_id == PXB_DEVICE_PLX_PCIE))) { 1880*10187SKrishna.Elango@Sun.COM fic = 1; 1881*10187SKrishna.Elango@Sun.COM } 1882*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 1883*10187SKrishna.Elango@Sun.COM if ((fic == 0) && ((PCI_CAP_LOCATE(config_handle, 1884*10187SKrishna.Elango@Sun.COM PCI_CAP_ID_SLOT_ID, &cap_ptr)) != DDI_FAILURE)) { 1885*10187SKrishna.Elango@Sun.COM uint8_t esr = PCI_CAP_GET8(config_handle, NULL, 1886*10187SKrishna.Elango@Sun.COM cap_ptr, PCI_CAP_ID_REGS_OFF); 1887*10187SKrishna.Elango@Sun.COM if (PCI_CAPSLOT_FIC(esr)) 1888*10187SKrishna.Elango@Sun.COM fic = 1; 1889*10187SKrishna.Elango@Sun.COM } 1890*10187SKrishna.Elango@Sun.COM 1891*10187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, 1892*10187SKrishna.Elango@Sun.COM PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_SER), &cap_ptr)) != DDI_FAILURE) { 1893*10187SKrishna.Elango@Sun.COM /* Serialid can be 0 thru a full 40b number */ 1894*10187SKrishna.Elango@Sun.COM serialid = PCI_XCAP_GET32(config_handle, NULL, 1895*10187SKrishna.Elango@Sun.COM cap_ptr, PCIE_SER_SID_UPPER_DW); 1896*10187SKrishna.Elango@Sun.COM serialid <<= 32; 1897*10187SKrishna.Elango@Sun.COM serialid |= PCI_XCAP_GET32(config_handle, NULL, 1898*10187SKrishna.Elango@Sun.COM cap_ptr, PCIE_SER_SID_LOWER_DW); 1899*10187SKrishna.Elango@Sun.COM } 1900*10187SKrishna.Elango@Sun.COM 1901*10187SKrishna.Elango@Sun.COM if (fic) 1902*10187SKrishna.Elango@Sun.COM (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip, 1903*10187SKrishna.Elango@Sun.COM "first-in-chassis"); 1904*10187SKrishna.Elango@Sun.COM if (serialid) 1905*10187SKrishna.Elango@Sun.COM (void) ddi_prop_update_int64(DDI_DEV_T_NONE, pcieb->pcieb_dip, 1906*10187SKrishna.Elango@Sun.COM "serialid#", serialid); 1907*10187SKrishna.Elango@Sun.COM } 1908*10187SKrishna.Elango@Sun.COM 1909*10187SKrishna.Elango@Sun.COM static void 1910*10187SKrishna.Elango@Sun.COM pcieb_create_ranges_prop(dev_info_t *dip, 1911*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle) 1912*10187SKrishna.Elango@Sun.COM { 1913*10187SKrishna.Elango@Sun.COM uint32_t base, limit; 1914*10187SKrishna.Elango@Sun.COM pcieb_ranges_t ranges[PCIEB_RANGE_LEN]; 1915*10187SKrishna.Elango@Sun.COM uint8_t io_base_lo, io_limit_lo; 1916*10187SKrishna.Elango@Sun.COM uint16_t io_base_hi, io_limit_hi, mem_base, mem_limit; 1917*10187SKrishna.Elango@Sun.COM int i = 0, rangelen = sizeof (pcieb_ranges_t)/sizeof (int); 1918*10187SKrishna.Elango@Sun.COM 1919*10187SKrishna.Elango@Sun.COM io_base_lo = pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW); 1920*10187SKrishna.Elango@Sun.COM io_limit_lo = pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW); 1921*10187SKrishna.Elango@Sun.COM io_base_hi = pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI); 1922*10187SKrishna.Elango@Sun.COM io_limit_hi = pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI); 1923*10187SKrishna.Elango@Sun.COM mem_base = pci_config_get16(config_handle, PCI_BCNF_MEM_BASE); 1924*10187SKrishna.Elango@Sun.COM mem_limit = pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT); 1925*10187SKrishna.Elango@Sun.COM 1926*10187SKrishna.Elango@Sun.COM /* 1927*10187SKrishna.Elango@Sun.COM * Create ranges for IO space 1928*10187SKrishna.Elango@Sun.COM */ 1929*10187SKrishna.Elango@Sun.COM ranges[i].size_low = ranges[i].size_high = 0; 1930*10187SKrishna.Elango@Sun.COM ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0; 1931*10187SKrishna.Elango@Sun.COM ranges[i].child_high = ranges[i].parent_high |= 1932*10187SKrishna.Elango@Sun.COM (PCI_REG_REL_M | PCI_ADDR_IO); 1933*10187SKrishna.Elango@Sun.COM base = PCIEB_16bit_IOADDR(io_base_lo); 1934*10187SKrishna.Elango@Sun.COM limit = PCIEB_16bit_IOADDR(io_limit_lo); 1935*10187SKrishna.Elango@Sun.COM 1936*10187SKrishna.Elango@Sun.COM if ((io_base_lo & 0xf) == PCIEB_32BIT_IO) { 1937*10187SKrishna.Elango@Sun.COM base = PCIEB_LADDR(base, io_base_hi); 1938*10187SKrishna.Elango@Sun.COM } 1939*10187SKrishna.Elango@Sun.COM if ((io_limit_lo & 0xf) == PCIEB_32BIT_IO) { 1940*10187SKrishna.Elango@Sun.COM limit = PCIEB_LADDR(limit, io_limit_hi); 1941*10187SKrishna.Elango@Sun.COM } 1942*10187SKrishna.Elango@Sun.COM 1943*10187SKrishna.Elango@Sun.COM if ((io_base_lo & PCIEB_32BIT_IO) && (io_limit_hi > 0)) { 1944*10187SKrishna.Elango@Sun.COM base = PCIEB_LADDR(base, io_base_hi); 1945*10187SKrishna.Elango@Sun.COM limit = PCIEB_LADDR(limit, io_limit_hi); 1946*10187SKrishna.Elango@Sun.COM } 1947*10187SKrishna.Elango@Sun.COM 1948*10187SKrishna.Elango@Sun.COM /* 1949*10187SKrishna.Elango@Sun.COM * Create ranges for 32bit memory space 1950*10187SKrishna.Elango@Sun.COM */ 1951*10187SKrishna.Elango@Sun.COM base = PCIEB_32bit_MEMADDR(mem_base); 1952*10187SKrishna.Elango@Sun.COM limit = PCIEB_32bit_MEMADDR(mem_limit); 1953*10187SKrishna.Elango@Sun.COM ranges[i].size_low = ranges[i].size_high = 0; 1954*10187SKrishna.Elango@Sun.COM ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0; 1955*10187SKrishna.Elango@Sun.COM ranges[i].child_high = ranges[i].parent_high |= 1956*10187SKrishna.Elango@Sun.COM (PCI_REG_REL_M | PCI_ADDR_MEM32); 1957*10187SKrishna.Elango@Sun.COM ranges[i].child_low = ranges[i].parent_low = base; 1958*10187SKrishna.Elango@Sun.COM if (limit >= base) { 1959*10187SKrishna.Elango@Sun.COM ranges[i].size_low = limit - base + PCIEB_MEMGRAIN; 1960*10187SKrishna.Elango@Sun.COM i++; 1961*10187SKrishna.Elango@Sun.COM } 1962*10187SKrishna.Elango@Sun.COM 1963*10187SKrishna.Elango@Sun.COM if (i) { 1964*10187SKrishna.Elango@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", 1965*10187SKrishna.Elango@Sun.COM (int *)ranges, i * rangelen); 1966*10187SKrishna.Elango@Sun.COM } 1967*10187SKrishna.Elango@Sun.COM } 1968*10187SKrishna.Elango@Sun.COM 1969*10187SKrishna.Elango@Sun.COM /* 1970*10187SKrishna.Elango@Sun.COM * For PCI and PCI-X devices including PCIe2PCI bridge, initialize 1971*10187SKrishna.Elango@Sun.COM * cache-line-size and latency timer configuration registers. 1972*10187SKrishna.Elango@Sun.COM */ 1973*10187SKrishna.Elango@Sun.COM void 1974*10187SKrishna.Elango@Sun.COM pcieb_set_pci_perf_parameters(dev_info_t *dip, ddi_acc_handle_t cfg_hdl) 1975*10187SKrishna.Elango@Sun.COM { 1976*10187SKrishna.Elango@Sun.COM uint_t n; 1977*10187SKrishna.Elango@Sun.COM 1978*10187SKrishna.Elango@Sun.COM /* Initialize cache-line-size configuration register if needed */ 1979*10187SKrishna.Elango@Sun.COM if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1980*10187SKrishna.Elango@Sun.COM "cache-line-size", 0) == 0) { 1981*10187SKrishna.Elango@Sun.COM pci_config_put8(cfg_hdl, PCI_CONF_CACHE_LINESZ, 1982*10187SKrishna.Elango@Sun.COM PCIEB_CACHE_LINE_SIZE); 1983*10187SKrishna.Elango@Sun.COM n = pci_config_get8(cfg_hdl, PCI_CONF_CACHE_LINESZ); 1984*10187SKrishna.Elango@Sun.COM if (n != 0) { 1985*10187SKrishna.Elango@Sun.COM (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 1986*10187SKrishna.Elango@Sun.COM "cache-line-size", n); 1987*10187SKrishna.Elango@Sun.COM } 1988*10187SKrishna.Elango@Sun.COM } 1989*10187SKrishna.Elango@Sun.COM 1990*10187SKrishna.Elango@Sun.COM /* Initialize latency timer configuration registers if needed */ 1991*10187SKrishna.Elango@Sun.COM if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1992*10187SKrishna.Elango@Sun.COM "latency-timer", 0) == 0) { 1993*10187SKrishna.Elango@Sun.COM uchar_t min_gnt, latency_timer; 1994*10187SKrishna.Elango@Sun.COM uchar_t header_type; 1995*10187SKrishna.Elango@Sun.COM 1996*10187SKrishna.Elango@Sun.COM /* Determine the configuration header type */ 1997*10187SKrishna.Elango@Sun.COM header_type = pci_config_get8(cfg_hdl, PCI_CONF_HEADER); 1998*10187SKrishna.Elango@Sun.COM 1999*10187SKrishna.Elango@Sun.COM if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 2000*10187SKrishna.Elango@Sun.COM latency_timer = PCIEB_LATENCY_TIMER; 2001*10187SKrishna.Elango@Sun.COM pci_config_put8(cfg_hdl, PCI_BCNF_LATENCY_TIMER, 2002*10187SKrishna.Elango@Sun.COM latency_timer); 2003*10187SKrishna.Elango@Sun.COM } else { 2004*10187SKrishna.Elango@Sun.COM min_gnt = pci_config_get8(cfg_hdl, PCI_CONF_MIN_G); 2005*10187SKrishna.Elango@Sun.COM latency_timer = min_gnt * 8; 2006*10187SKrishna.Elango@Sun.COM } 2007*10187SKrishna.Elango@Sun.COM 2008*10187SKrishna.Elango@Sun.COM pci_config_put8(cfg_hdl, PCI_CONF_LATENCY_TIMER, 2009*10187SKrishna.Elango@Sun.COM latency_timer); 2010*10187SKrishna.Elango@Sun.COM n = pci_config_get8(cfg_hdl, PCI_CONF_LATENCY_TIMER); 2011*10187SKrishna.Elango@Sun.COM if (n != 0) { 2012*10187SKrishna.Elango@Sun.COM (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 2013*10187SKrishna.Elango@Sun.COM "latency-timer", n); 2014*10187SKrishna.Elango@Sun.COM } 2015*10187SKrishna.Elango@Sun.COM } 2016*10187SKrishna.Elango@Sun.COM } 2017