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