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 /* SPARC specific code used by the pcieb driver */ 27*10187SKrishna.Elango@Sun.COM 28*10187SKrishna.Elango@Sun.COM #include <sys/types.h> 29*10187SKrishna.Elango@Sun.COM #include <sys/ddi.h> 30*10187SKrishna.Elango@Sun.COM #include <sys/kmem.h> 31*10187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h> 32*10187SKrishna.Elango@Sun.COM #include <sys/sunddi.h> 33*10187SKrishna.Elango@Sun.COM #include <sys/sunndi.h> 34*10187SKrishna.Elango@Sun.COM #include <sys/pcie.h> 35*10187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h> 36*10187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h> 37*10187SKrishna.Elango@Sun.COM #include <io/pciex/pcieb.h> 38*10187SKrishna.Elango@Sun.COM #include "pcieb_plx.h" 39*10187SKrishna.Elango@Sun.COM 40*10187SKrishna.Elango@Sun.COM /*LINTLIBRARY*/ 41*10187SKrishna.Elango@Sun.COM 42*10187SKrishna.Elango@Sun.COM /* PLX specific functions */ 43*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX 44*10187SKrishna.Elango@Sun.COM static void plx_ro_disable(pcieb_devstate_t *pcieb); 45*10187SKrishna.Elango@Sun.COM #ifdef PRINT_PLX_SEEPROM_CRC 46*10187SKrishna.Elango@Sun.COM static void pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p); 47*10187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */ 48*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 49*10187SKrishna.Elango@Sun.COM 50*10187SKrishna.Elango@Sun.COM int 51*10187SKrishna.Elango@Sun.COM pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 52*10187SKrishna.Elango@Sun.COM void *arg, void *result) 53*10187SKrishna.Elango@Sun.COM { 54*10187SKrishna.Elango@Sun.COM return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 55*10187SKrishna.Elango@Sun.COM } 56*10187SKrishna.Elango@Sun.COM 57*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 58*10187SKrishna.Elango@Sun.COM void 59*10187SKrishna.Elango@Sun.COM pcieb_plat_attach_workaround(dev_info_t *dip) 60*10187SKrishna.Elango@Sun.COM { 61*10187SKrishna.Elango@Sun.COM } 62*10187SKrishna.Elango@Sun.COM 63*10187SKrishna.Elango@Sun.COM int 64*10187SKrishna.Elango@Sun.COM pcieb_plat_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 65*10187SKrishna.Elango@Sun.COM ddi_intr_handle_impl_t *hdlp, void *result) 66*10187SKrishna.Elango@Sun.COM { 67*10187SKrishna.Elango@Sun.COM dev_info_t *cdip = rdip; 68*10187SKrishna.Elango@Sun.COM pci_regspec_t *pci_rp; 69*10187SKrishna.Elango@Sun.COM int reglen, len; 70*10187SKrishna.Elango@Sun.COM uint32_t d, intr; 71*10187SKrishna.Elango@Sun.COM 72*10187SKrishna.Elango@Sun.COM if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || 73*10187SKrishna.Elango@Sun.COM (hdlp->ih_type != DDI_INTR_TYPE_FIXED)) 74*10187SKrishna.Elango@Sun.COM goto done; 75*10187SKrishna.Elango@Sun.COM 76*10187SKrishna.Elango@Sun.COM /* 77*10187SKrishna.Elango@Sun.COM * If the interrupt-map property is defined at this 78*10187SKrishna.Elango@Sun.COM * node, it will have performed the interrupt 79*10187SKrishna.Elango@Sun.COM * translation as part of the property, so no 80*10187SKrishna.Elango@Sun.COM * rotation needs to be done. 81*10187SKrishna.Elango@Sun.COM */ 82*10187SKrishna.Elango@Sun.COM if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 83*10187SKrishna.Elango@Sun.COM "interrupt-map", &len) == DDI_PROP_SUCCESS) 84*10187SKrishna.Elango@Sun.COM goto done; 85*10187SKrishna.Elango@Sun.COM 86*10187SKrishna.Elango@Sun.COM cdip = pcie_get_my_childs_dip(dip, rdip); 87*10187SKrishna.Elango@Sun.COM 88*10187SKrishna.Elango@Sun.COM /* 89*10187SKrishna.Elango@Sun.COM * Use the devices reg property to determine its 90*10187SKrishna.Elango@Sun.COM * PCI bus number and device number. 91*10187SKrishna.Elango@Sun.COM */ 92*10187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 93*10187SKrishna.Elango@Sun.COM "reg", (caddr_t)&pci_rp, ®len) != DDI_SUCCESS) 94*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 95*10187SKrishna.Elango@Sun.COM 96*10187SKrishna.Elango@Sun.COM intr = hdlp->ih_vector; 97*10187SKrishna.Elango@Sun.COM 98*10187SKrishna.Elango@Sun.COM /* spin the interrupt */ 99*10187SKrishna.Elango@Sun.COM d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); 100*10187SKrishna.Elango@Sun.COM if ((intr >= PCI_INTA) && (intr <= PCI_INTD)) 101*10187SKrishna.Elango@Sun.COM hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1); 102*10187SKrishna.Elango@Sun.COM else 103*10187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range", 104*10187SKrishna.Elango@Sun.COM ddi_driver_name(rdip), ddi_get_instance(rdip), 105*10187SKrishna.Elango@Sun.COM ddi_driver_name(dip), intr); 106*10187SKrishna.Elango@Sun.COM 107*10187SKrishna.Elango@Sun.COM kmem_free(pci_rp, reglen); 108*10187SKrishna.Elango@Sun.COM 109*10187SKrishna.Elango@Sun.COM done: 110*10187SKrishna.Elango@Sun.COM /* Pass up the request to our parent. */ 111*10187SKrishna.Elango@Sun.COM return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)); 112*10187SKrishna.Elango@Sun.COM } 113*10187SKrishna.Elango@Sun.COM 114*10187SKrishna.Elango@Sun.COM int 115*10187SKrishna.Elango@Sun.COM pcieb_plat_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle) 116*10187SKrishna.Elango@Sun.COM { 117*10187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 118*10187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_HOTPLUG, &cap_ptr)) != 119*10187SKrishna.Elango@Sun.COM DDI_FAILURE) { 120*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 121*10187SKrishna.Elango@Sun.COM } 122*10187SKrishna.Elango@Sun.COM 123*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 124*10187SKrishna.Elango@Sun.COM } 125*10187SKrishna.Elango@Sun.COM 126*10187SKrishna.Elango@Sun.COM /* 127*10187SKrishna.Elango@Sun.COM * Disable PM on PLX. For PLX Transitioning one port on this switch to 128*10187SKrishna.Elango@Sun.COM * low power causes links on other ports on the same station to die. 129*10187SKrishna.Elango@Sun.COM * Due to PLX erratum #34, we can't allow the downstream device go to 130*10187SKrishna.Elango@Sun.COM * non-D0 state. 131*10187SKrishna.Elango@Sun.COM */ 132*10187SKrishna.Elango@Sun.COM boolean_t 133*10187SKrishna.Elango@Sun.COM pcieb_plat_pwr_disable(dev_info_t *dip) 134*10187SKrishna.Elango@Sun.COM { 135*10187SKrishna.Elango@Sun.COM uint16_t vendor_id = (PCIE_DIP2UPBUS(dip)->bus_dev_ven_id) & 0xFFFF; 136*10187SKrishna.Elango@Sun.COM return (IS_PLX_VENDORID(vendor_id) ? B_TRUE : B_FALSE); 137*10187SKrishna.Elango@Sun.COM } 138*10187SKrishna.Elango@Sun.COM 139*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 140*10187SKrishna.Elango@Sun.COM boolean_t 141*10187SKrishna.Elango@Sun.COM pcieb_plat_msi_supported(dev_info_t *dip) 142*10187SKrishna.Elango@Sun.COM { 143*10187SKrishna.Elango@Sun.COM return (B_TRUE); 144*10187SKrishna.Elango@Sun.COM } 145*10187SKrishna.Elango@Sun.COM 146*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 147*10187SKrishna.Elango@Sun.COM void 148*10187SKrishna.Elango@Sun.COM pcieb_plat_intr_attach(pcieb_devstate_t *pcieb) 149*10187SKrishna.Elango@Sun.COM { 150*10187SKrishna.Elango@Sun.COM } 151*10187SKrishna.Elango@Sun.COM 152*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 153*10187SKrishna.Elango@Sun.COM int 154*10187SKrishna.Elango@Sun.COM pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg) 155*10187SKrishna.Elango@Sun.COM { 156*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 157*10187SKrishna.Elango@Sun.COM } 158*10187SKrishna.Elango@Sun.COM 159*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 160*10187SKrishna.Elango@Sun.COM void 161*10187SKrishna.Elango@Sun.COM pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd) 162*10187SKrishna.Elango@Sun.COM { 163*10187SKrishna.Elango@Sun.COM } 164*10187SKrishna.Elango@Sun.COM 165*10187SKrishna.Elango@Sun.COM void 166*10187SKrishna.Elango@Sun.COM pcieb_plat_initchild(dev_info_t *child) 167*10187SKrishna.Elango@Sun.COM { 168*10187SKrishna.Elango@Sun.COM intptr_t ppd = NULL; 169*10187SKrishna.Elango@Sun.COM /* 170*10187SKrishna.Elango@Sun.COM * XXX set ppd to 1 to disable iommu BDF protection on SPARC. 171*10187SKrishna.Elango@Sun.COM * It relies on unused parent private data for PCI devices. 172*10187SKrishna.Elango@Sun.COM */ 173*10187SKrishna.Elango@Sun.COM if (ddi_prop_exists(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, 174*10187SKrishna.Elango@Sun.COM "dvma-share")) 175*10187SKrishna.Elango@Sun.COM ppd = 1; 176*10187SKrishna.Elango@Sun.COM 177*10187SKrishna.Elango@Sun.COM ddi_set_parent_data(child, (void *)ppd); 178*10187SKrishna.Elango@Sun.COM } 179*10187SKrishna.Elango@Sun.COM 180*10187SKrishna.Elango@Sun.COM void 181*10187SKrishna.Elango@Sun.COM pcieb_plat_uninitchild(dev_info_t *child) 182*10187SKrishna.Elango@Sun.COM { 183*10187SKrishna.Elango@Sun.COM /* 184*10187SKrishna.Elango@Sun.COM * XXX Clear parent private data used as a flag to disable 185*10187SKrishna.Elango@Sun.COM * iommu BDF protection 186*10187SKrishna.Elango@Sun.COM */ 187*10187SKrishna.Elango@Sun.COM if ((intptr_t)ddi_get_parent_data(child) == 1) 188*10187SKrishna.Elango@Sun.COM ddi_set_parent_data(child, NULL); 189*10187SKrishna.Elango@Sun.COM } 190*10187SKrishna.Elango@Sun.COM 191*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX 192*10187SKrishna.Elango@Sun.COM /* 193*10187SKrishna.Elango@Sun.COM * These are PLX specific workarounds needed during attach. 194*10187SKrishna.Elango@Sun.COM */ 195*10187SKrishna.Elango@Sun.COM void 196*10187SKrishna.Elango@Sun.COM pcieb_attach_plx_workarounds(pcieb_devstate_t *pcieb) 197*10187SKrishna.Elango@Sun.COM { 198*10187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb->pcieb_dip; 199*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 200*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl; 201*10187SKrishna.Elango@Sun.COM uint_t bus_num, primary, secondary; 202*10187SKrishna.Elango@Sun.COM uint8_t dev_type = bus_p->bus_dev_type; 203*10187SKrishna.Elango@Sun.COM uint16_t vendor_id = bus_p->bus_dev_ven_id & 0xFFFF; 204*10187SKrishna.Elango@Sun.COM 205*10187SKrishna.Elango@Sun.COM if (!IS_PLX_VENDORID(vendor_id)) 206*10187SKrishna.Elango@Sun.COM return; 207*10187SKrishna.Elango@Sun.COM 208*10187SKrishna.Elango@Sun.COM /* 209*10187SKrishna.Elango@Sun.COM * Due to a PLX HW bug we need to disable the receiver error CE on all 210*10187SKrishna.Elango@Sun.COM * ports. To this end we create a property "pcie_ce_mask" with value 211*10187SKrishna.Elango@Sun.COM * set to PCIE_AER_CE_RECEIVER_ERR. The pcie module will check for this 212*10187SKrishna.Elango@Sun.COM * property before setting the AER CE mask. 213*10187SKrishna.Elango@Sun.COM */ 214*10187SKrishna.Elango@Sun.COM (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 215*10187SKrishna.Elango@Sun.COM "pcie_ce_mask", PCIE_AER_CE_RECEIVER_ERR); 216*10187SKrishna.Elango@Sun.COM 217*10187SKrishna.Elango@Sun.COM /* 218*10187SKrishna.Elango@Sun.COM * There is a bug in the PLX 8114 bridge, such that an 8-bit 219*10187SKrishna.Elango@Sun.COM * write to the secondary bus number register will corrupt an 220*10187SKrishna.Elango@Sun.COM * internal shadow copy of the primary bus number. Reading 221*10187SKrishna.Elango@Sun.COM * out the registers and writing the same values back as 222*10187SKrishna.Elango@Sun.COM * 16-bits resolves the problem. This bug was reported by 223*10187SKrishna.Elango@Sun.COM * PLX as errata #19. 224*10187SKrishna.Elango@Sun.COM */ 225*10187SKrishna.Elango@Sun.COM primary = pci_config_get8(config_handle, PCI_BCNF_PRIBUS); 226*10187SKrishna.Elango@Sun.COM secondary = pci_config_get8(config_handle, PCI_BCNF_SECBUS); 227*10187SKrishna.Elango@Sun.COM bus_num = (secondary << 8) | primary; 228*10187SKrishna.Elango@Sun.COM pci_config_put16(config_handle, PCI_BCNF_PRIBUS, bus_num); 229*10187SKrishna.Elango@Sun.COM 230*10187SKrishna.Elango@Sun.COM /* 231*10187SKrishna.Elango@Sun.COM * Workaround for a race condition between hotplug 232*10187SKrishna.Elango@Sun.COM * initialization and actual MSI interrupt registration 233*10187SKrishna.Elango@Sun.COM * for hotplug functionality. The hotplug initialization 234*10187SKrishna.Elango@Sun.COM * generates an INTx interrupt for hotplug events and this 235*10187SKrishna.Elango@Sun.COM * INTx interrupt may interfere with shared leaf drivers 236*10187SKrishna.Elango@Sun.COM * using same INTx interrupt, which may eventually block 237*10187SKrishna.Elango@Sun.COM * the leaf drivers. 238*10187SKrishna.Elango@Sun.COM */ 239*10187SKrishna.Elango@Sun.COM if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) || 240*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) || 241*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) || 242*10187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) { 243*10187SKrishna.Elango@Sun.COM pci_config_put16(config_handle, PCI_CONF_COMM, 244*10187SKrishna.Elango@Sun.COM pci_config_get16(config_handle, PCI_CONF_COMM) | 245*10187SKrishna.Elango@Sun.COM PCI_COMM_INTX_DISABLE); 246*10187SKrishna.Elango@Sun.COM } 247*10187SKrishna.Elango@Sun.COM 248*10187SKrishna.Elango@Sun.COM /* 249*10187SKrishna.Elango@Sun.COM * Disable PLX Special Relaxed Ordering 250*10187SKrishna.Elango@Sun.COM */ 251*10187SKrishna.Elango@Sun.COM plx_ro_disable(pcieb); 252*10187SKrishna.Elango@Sun.COM 253*10187SKrishna.Elango@Sun.COM #ifdef PRINT_PLX_SEEPROM_CRC 254*10187SKrishna.Elango@Sun.COM /* check seeprom CRC to ensure the platform config is right */ 255*10187SKrishna.Elango@Sun.COM (void) pcieb_print_plx_seeprom_crc_data(pcieb); 256*10187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */ 257*10187SKrishna.Elango@Sun.COM } 258*10187SKrishna.Elango@Sun.COM 259*10187SKrishna.Elango@Sun.COM /* 260*10187SKrishna.Elango@Sun.COM * These are PLX specific workarounds called during child's initchild. 261*10187SKrishna.Elango@Sun.COM */ 262*10187SKrishna.Elango@Sun.COM int 263*10187SKrishna.Elango@Sun.COM pcieb_init_plx_workarounds(pcieb_devstate_t *pcieb, dev_info_t *child) 264*10187SKrishna.Elango@Sun.COM { 265*10187SKrishna.Elango@Sun.COM int i; 266*10187SKrishna.Elango@Sun.COM int result = DDI_FAILURE; 267*10187SKrishna.Elango@Sun.COM uint16_t reg = 0; 268*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 269*10187SKrishna.Elango@Sun.COM uint16_t vendor_id = 270*10187SKrishna.Elango@Sun.COM (PCIE_DIP2UPBUS(pcieb->pcieb_dip))->bus_dev_ven_id & 0xFFFF; 271*10187SKrishna.Elango@Sun.COM 272*10187SKrishna.Elango@Sun.COM if (!IS_PLX_VENDORID(vendor_id)) 273*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 274*10187SKrishna.Elango@Sun.COM 275*10187SKrishna.Elango@Sun.COM /* 276*10187SKrishna.Elango@Sun.COM * Due to a PLX HW bug, a SW workaround to prevent the chip from 277*10187SKrishna.Elango@Sun.COM * wedging is needed. SW just needs to tranfer 64 TLPs from 278*10187SKrishna.Elango@Sun.COM * the downstream port to the child device. 279*10187SKrishna.Elango@Sun.COM * The most benign way of doing this is to read the ID register 280*10187SKrishna.Elango@Sun.COM * 64 times. This SW workaround should have minimum performance 281*10187SKrishna.Elango@Sun.COM * impact and shouldn't cause a problem for all other bridges 282*10187SKrishna.Elango@Sun.COM * and switches. 283*10187SKrishna.Elango@Sun.COM * 284*10187SKrishna.Elango@Sun.COM * The code needs to be written in a way to make sure it isn't 285*10187SKrishna.Elango@Sun.COM * optimized out. 286*10187SKrishna.Elango@Sun.COM */ 287*10187SKrishna.Elango@Sun.COM if (!pxb_tlp_count) { 288*10187SKrishna.Elango@Sun.COM result = DDI_SUCCESS; 289*10187SKrishna.Elango@Sun.COM goto done; 290*10187SKrishna.Elango@Sun.COM } 291*10187SKrishna.Elango@Sun.COM 292*10187SKrishna.Elango@Sun.COM if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { 293*10187SKrishna.Elango@Sun.COM result = DDI_FAILURE; 294*10187SKrishna.Elango@Sun.COM goto done; 295*10187SKrishna.Elango@Sun.COM } 296*10187SKrishna.Elango@Sun.COM 297*10187SKrishna.Elango@Sun.COM for (i = 0; i < pxb_tlp_count; i += 1) 298*10187SKrishna.Elango@Sun.COM reg |= pci_config_get16(config_handle, PCI_CONF_VENID); 299*10187SKrishna.Elango@Sun.COM 300*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(pcieb->pcieb_dip))) 301*10187SKrishna.Elango@Sun.COM pcieb_set_pci_perf_parameters(child, config_handle); 302*10187SKrishna.Elango@Sun.COM 303*10187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 304*10187SKrishna.Elango@Sun.COM result = DDI_SUCCESS; 305*10187SKrishna.Elango@Sun.COM done: 306*10187SKrishna.Elango@Sun.COM return (result); 307*10187SKrishna.Elango@Sun.COM } 308*10187SKrishna.Elango@Sun.COM 309*10187SKrishna.Elango@Sun.COM /* 310*10187SKrishna.Elango@Sun.COM * Disable PLX specific relaxed ordering mode. Due to PLX 311*10187SKrishna.Elango@Sun.COM * erratum #6, use of this mode with Cut-Through Cancellation 312*10187SKrishna.Elango@Sun.COM * can result in dropped Completion type packets. 313*10187SKrishna.Elango@Sun.COM * 314*10187SKrishna.Elango@Sun.COM * Clear the Relaxed Ordering Mode on 8533 and 8548 switches. 315*10187SKrishna.Elango@Sun.COM * To disable RO, clear bit 5 in offset 0x664, an undocumented 316*10187SKrishna.Elango@Sun.COM * bit in the PLX spec, on Ports 0, 8 and 12. Proprietary PLX 317*10187SKrishna.Elango@Sun.COM * registers are normally accessible only via memspace from Port 318*10187SKrishna.Elango@Sun.COM * 0. If port 0 is attached go ahead and disable RO on Port 0, 319*10187SKrishna.Elango@Sun.COM * 8 and 12, if they exist. 320*10187SKrishna.Elango@Sun.COM */ 321*10187SKrishna.Elango@Sun.COM static void 322*10187SKrishna.Elango@Sun.COM plx_ro_disable(pcieb_devstate_t *pcieb) 323*10187SKrishna.Elango@Sun.COM { 324*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip); 325*10187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb->pcieb_dip; 326*10187SKrishna.Elango@Sun.COM uint16_t device_id = bus_p->bus_dev_ven_id >> 16; 327*10187SKrishna.Elango@Sun.COM pci_regspec_t *reg_spec, *addr_spec; 328*10187SKrishna.Elango@Sun.COM int rlen, alen; 329*10187SKrishna.Elango@Sun.COM int orig_rsize, new_rsize; 330*10187SKrishna.Elango@Sun.COM uint_t rnum, anum; 331*10187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t attr; 332*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t hdl; 333*10187SKrishna.Elango@Sun.COM caddr_t regsp; 334*10187SKrishna.Elango@Sun.COM uint32_t val, port_enable; 335*10187SKrishna.Elango@Sun.COM char *offset; 336*10187SKrishna.Elango@Sun.COM char *port_offset; 337*10187SKrishna.Elango@Sun.COM 338*10187SKrishna.Elango@Sun.COM if (!((device_id == PXB_DEVICE_PLX_8533) || 339*10187SKrishna.Elango@Sun.COM (device_id == PXB_DEVICE_PLX_8548))) 340*10187SKrishna.Elango@Sun.COM return; 341*10187SKrishna.Elango@Sun.COM 342*10187SKrishna.Elango@Sun.COM /* You can also only do this on Port 0 */ 343*10187SKrishna.Elango@Sun.COM val = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP); 344*10187SKrishna.Elango@Sun.COM val = (val >> PCIE_LINKCAP_PORT_NUMBER_SHIFT) & 345*10187SKrishna.Elango@Sun.COM PCIE_LINKCAP_PORT_NUMBER_MASK; 346*10187SKrishna.Elango@Sun.COM 347*10187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "PLX RO Disable : bdf=0x%x port=%d\n", 348*10187SKrishna.Elango@Sun.COM bus_p->bus_bdf, val); 349*10187SKrishna.Elango@Sun.COM 350*10187SKrishna.Elango@Sun.COM if (val != 0) 351*10187SKrishna.Elango@Sun.COM return; 352*10187SKrishna.Elango@Sun.COM 353*10187SKrishna.Elango@Sun.COM /* 354*10187SKrishna.Elango@Sun.COM * Read the reg property, but allocate extra space incase we need to add 355*10187SKrishna.Elango@Sun.COM * a new entry later. 356*10187SKrishna.Elango@Sun.COM */ 357*10187SKrishna.Elango@Sun.COM if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 358*10187SKrishna.Elango@Sun.COM &orig_rsize) != DDI_SUCCESS) 359*10187SKrishna.Elango@Sun.COM return; 360*10187SKrishna.Elango@Sun.COM 361*10187SKrishna.Elango@Sun.COM new_rsize = orig_rsize + sizeof (pci_regspec_t); 362*10187SKrishna.Elango@Sun.COM reg_spec = kmem_alloc(new_rsize, KM_SLEEP); 363*10187SKrishna.Elango@Sun.COM 364*10187SKrishna.Elango@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 365*10187SKrishna.Elango@Sun.COM (caddr_t)reg_spec, &orig_rsize) != DDI_SUCCESS) 366*10187SKrishna.Elango@Sun.COM goto fail; 367*10187SKrishna.Elango@Sun.COM 368*10187SKrishna.Elango@Sun.COM /* Find the mem32 reg property */ 369*10187SKrishna.Elango@Sun.COM rlen = orig_rsize / sizeof (pci_regspec_t); 370*10187SKrishna.Elango@Sun.COM for (rnum = 0; rnum < rlen; rnum++) { 371*10187SKrishna.Elango@Sun.COM if ((reg_spec[rnum].pci_phys_hi & PCI_ADDR_MASK) == 372*10187SKrishna.Elango@Sun.COM PCI_ADDR_MEM32) 373*10187SKrishna.Elango@Sun.COM goto fix; 374*10187SKrishna.Elango@Sun.COM } 375*10187SKrishna.Elango@Sun.COM 376*10187SKrishna.Elango@Sun.COM /* 377*10187SKrishna.Elango@Sun.COM * Mem32 reg property was not found. 378*10187SKrishna.Elango@Sun.COM * Look for it in assign-address property. 379*10187SKrishna.Elango@Sun.COM */ 380*10187SKrishna.Elango@Sun.COM addr_spec = bus_p->bus_assigned_addr; 381*10187SKrishna.Elango@Sun.COM alen = bus_p->bus_assigned_entries; 382*10187SKrishna.Elango@Sun.COM for (anum = 0; anum < alen; anum++) { 383*10187SKrishna.Elango@Sun.COM if ((addr_spec[anum].pci_phys_hi & PCI_ADDR_MASK) == 384*10187SKrishna.Elango@Sun.COM PCI_ADDR_MEM32) 385*10187SKrishna.Elango@Sun.COM goto update; 386*10187SKrishna.Elango@Sun.COM } 387*10187SKrishna.Elango@Sun.COM 388*10187SKrishna.Elango@Sun.COM /* Unable to find mem space assigned address, give up. */ 389*10187SKrishna.Elango@Sun.COM goto fail; 390*10187SKrishna.Elango@Sun.COM 391*10187SKrishna.Elango@Sun.COM update: 392*10187SKrishna.Elango@Sun.COM /* 393*10187SKrishna.Elango@Sun.COM * Add the mem32 access to the reg spec. 394*10187SKrishna.Elango@Sun.COM * Use the last entry which was previously allocated. 395*10187SKrishna.Elango@Sun.COM */ 396*10187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_phys_hi = (addr_spec[anum].pci_phys_hi & 397*10187SKrishna.Elango@Sun.COM ~PCI_REG_REL_M); 398*10187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_phys_mid = 0; 399*10187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_phys_low = 0; 400*10187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_size_hi = addr_spec[anum].pci_size_hi; 401*10187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_size_low = addr_spec[anum].pci_size_low; 402*10187SKrishna.Elango@Sun.COM 403*10187SKrishna.Elango@Sun.COM /* Create the new reg_spec data and update the property */ 404*10187SKrishna.Elango@Sun.COM if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", 405*10187SKrishna.Elango@Sun.COM (int *)reg_spec, (new_rsize / sizeof (int))) != DDI_SUCCESS) 406*10187SKrishna.Elango@Sun.COM goto fail; 407*10187SKrishna.Elango@Sun.COM 408*10187SKrishna.Elango@Sun.COM fix: 409*10187SKrishna.Elango@Sun.COM attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 410*10187SKrishna.Elango@Sun.COM attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 411*10187SKrishna.Elango@Sun.COM attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 412*10187SKrishna.Elango@Sun.COM 413*10187SKrishna.Elango@Sun.COM if (ddi_regs_map_setup(dip, rnum, ®sp, 0, 0, &attr, 414*10187SKrishna.Elango@Sun.COM &hdl) != DDI_SUCCESS) 415*10187SKrishna.Elango@Sun.COM goto fail; 416*10187SKrishna.Elango@Sun.COM 417*10187SKrishna.Elango@Sun.COM /* Grab register which shows which ports are enabled */ 418*10187SKrishna.Elango@Sun.COM offset = (char *)regsp + PLX_INGRESS_PORT_ENABLE; 419*10187SKrishna.Elango@Sun.COM port_enable = ddi_get32(hdl, (uint32_t *)offset); 420*10187SKrishna.Elango@Sun.COM 421*10187SKrishna.Elango@Sun.COM if ((port_enable == 0xFFFFFFFF) || (port_enable == 0)) 422*10187SKrishna.Elango@Sun.COM goto done; 423*10187SKrishna.Elango@Sun.COM 424*10187SKrishna.Elango@Sun.COM offset = (char *)regsp + PLX_INGRESS_CONTROL_SHADOW; 425*10187SKrishna.Elango@Sun.COM 426*10187SKrishna.Elango@Sun.COM /* Disable RO on Port 0 */ 427*10187SKrishna.Elango@Sun.COM port_offset = 0x0 + offset; 428*10187SKrishna.Elango@Sun.COM val = ddi_get32(hdl, (uint32_t *)port_offset); 429*10187SKrishna.Elango@Sun.COM if (val & PLX_RO_MODE_BIT) 430*10187SKrishna.Elango@Sun.COM val ^= PLX_RO_MODE_BIT; 431*10187SKrishna.Elango@Sun.COM ddi_put32(hdl, (uint32_t *)port_offset, val); 432*10187SKrishna.Elango@Sun.COM 433*10187SKrishna.Elango@Sun.COM /* Disable RO on Port 8, but make sure its enabled */ 434*10187SKrishna.Elango@Sun.COM if (!(port_enable & (1 << 8))) 435*10187SKrishna.Elango@Sun.COM goto port12; 436*10187SKrishna.Elango@Sun.COM 437*10187SKrishna.Elango@Sun.COM port_offset = (8 * 0x1000) + offset; 438*10187SKrishna.Elango@Sun.COM val = ddi_get32(hdl, (uint32_t *)port_offset); 439*10187SKrishna.Elango@Sun.COM if (val & PLX_RO_MODE_BIT) 440*10187SKrishna.Elango@Sun.COM val ^= PLX_RO_MODE_BIT; 441*10187SKrishna.Elango@Sun.COM ddi_put32(hdl, (uint32_t *)port_offset, val); 442*10187SKrishna.Elango@Sun.COM 443*10187SKrishna.Elango@Sun.COM port12: 444*10187SKrishna.Elango@Sun.COM /* Disable RO on Port 12, but make sure it exists */ 445*10187SKrishna.Elango@Sun.COM if (!(port_enable & (1 << 12))) 446*10187SKrishna.Elango@Sun.COM goto done; 447*10187SKrishna.Elango@Sun.COM 448*10187SKrishna.Elango@Sun.COM port_offset = (12 * 0x1000) + offset; 449*10187SKrishna.Elango@Sun.COM val = ddi_get32(hdl, (uint32_t *)port_offset); 450*10187SKrishna.Elango@Sun.COM if (val & PLX_RO_MODE_BIT) 451*10187SKrishna.Elango@Sun.COM val ^= PLX_RO_MODE_BIT; 452*10187SKrishna.Elango@Sun.COM ddi_put32(hdl, (uint32_t *)port_offset, val); 453*10187SKrishna.Elango@Sun.COM 454*10187SKrishna.Elango@Sun.COM goto done; 455*10187SKrishna.Elango@Sun.COM 456*10187SKrishna.Elango@Sun.COM done: 457*10187SKrishna.Elango@Sun.COM ddi_regs_map_free(&hdl); 458*10187SKrishna.Elango@Sun.COM fail: 459*10187SKrishna.Elango@Sun.COM kmem_free(reg_spec, new_rsize); 460*10187SKrishna.Elango@Sun.COM } 461*10187SKrishna.Elango@Sun.COM 462*10187SKrishna.Elango@Sun.COM #ifdef PRINT_PLX_SEEPROM_CRC 463*10187SKrishna.Elango@Sun.COM static void 464*10187SKrishna.Elango@Sun.COM pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p) 465*10187SKrishna.Elango@Sun.COM { 466*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t h; 467*10187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb_p->pcieb_dip; 468*10187SKrishna.Elango@Sun.COM uint16_t vendorid = (PCIE_DIP2BUS(dip)->bus_dev_ven_id) & 0xFFFF; 469*10187SKrishna.Elango@Sun.COM int nregs; 470*10187SKrishna.Elango@Sun.COM caddr_t mp; 471*10187SKrishna.Elango@Sun.COM off_t bar_size; 472*10187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t mattr = { 473*10187SKrishna.Elango@Sun.COM DDI_DEVICE_ATTR_V0, 474*10187SKrishna.Elango@Sun.COM DDI_STRUCTURE_LE_ACC, 475*10187SKrishna.Elango@Sun.COM DDI_STRICTORDER_ACC 476*10187SKrishna.Elango@Sun.COM }; 477*10187SKrishna.Elango@Sun.COM uint32_t addr_reg_off = 0x260, data_reg_off = 0x264, data = 0x6BE4; 478*10187SKrishna.Elango@Sun.COM 479*10187SKrishna.Elango@Sun.COM if (vendorid != PXB_VENDOR_PLX) 480*10187SKrishna.Elango@Sun.COM return; 481*10187SKrishna.Elango@Sun.COM if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) 482*10187SKrishna.Elango@Sun.COM return; 483*10187SKrishna.Elango@Sun.COM if (nregs < 2) /* check for CONF entry only, no BARs */ 484*10187SKrishna.Elango@Sun.COM return; 485*10187SKrishna.Elango@Sun.COM if (ddi_dev_regsize(dip, 1, &bar_size) != DDI_SUCCESS) 486*10187SKrishna.Elango@Sun.COM return; 487*10187SKrishna.Elango@Sun.COM if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mp, 0, bar_size, 488*10187SKrishna.Elango@Sun.COM &mattr, &h) != DDI_SUCCESS) 489*10187SKrishna.Elango@Sun.COM return; 490*10187SKrishna.Elango@Sun.COM ddi_put32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off), data); 491*10187SKrishna.Elango@Sun.COM delay(drv_usectohz(1000000)); 492*10187SKrishna.Elango@Sun.COM printf("%s#%d: EEPROM StatusReg = %x, CRC = %x\n", 493*10187SKrishna.Elango@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), 494*10187SKrishna.Elango@Sun.COM ddi_get32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off)), 495*10187SKrishna.Elango@Sun.COM ddi_get32(h, (uint32_t *)((uchar_t *)mp + data_reg_off))); 496*10187SKrishna.Elango@Sun.COM #ifdef PLX_HOT_RESET_DISABLE 497*10187SKrishna.Elango@Sun.COM /* prevent hot reset from propogating downstream. */ 498*10187SKrishna.Elango@Sun.COM data = ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC)); 499*10187SKrishna.Elango@Sun.COM ddi_put32(h, (uint32_t *)((uchar_t *)mp + 0x1DC), data | 0x80000); 500*10187SKrishna.Elango@Sun.COM delay(drv_usectohz(1000000)); 501*10187SKrishna.Elango@Sun.COM printf("%s#%d: EEPROM 0x1DC prewrite=%x postwrite=%x\n", 502*10187SKrishna.Elango@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), data, 503*10187SKrishna.Elango@Sun.COM ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC))); 504*10187SKrishna.Elango@Sun.COM #endif /* PLX_HOT_RESET_DISABLE */ 505*10187SKrishna.Elango@Sun.COM ddi_regs_map_free(&h); 506*10187SKrishna.Elango@Sun.COM } 507*10187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */ 508*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 509