110187SKrishna.Elango@Sun.COM /* 210187SKrishna.Elango@Sun.COM * CDDL HEADER START 310187SKrishna.Elango@Sun.COM * 410187SKrishna.Elango@Sun.COM * The contents of this file are subject to the terms of the 510187SKrishna.Elango@Sun.COM * Common Development and Distribution License (the "License"). 610187SKrishna.Elango@Sun.COM * You may not use this file except in compliance with the License. 710187SKrishna.Elango@Sun.COM * 810187SKrishna.Elango@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910187SKrishna.Elango@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010187SKrishna.Elango@Sun.COM * See the License for the specific language governing permissions 1110187SKrishna.Elango@Sun.COM * and limitations under the License. 1210187SKrishna.Elango@Sun.COM * 1310187SKrishna.Elango@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410187SKrishna.Elango@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510187SKrishna.Elango@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610187SKrishna.Elango@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710187SKrishna.Elango@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810187SKrishna.Elango@Sun.COM * 1910187SKrishna.Elango@Sun.COM * CDDL HEADER END 2010187SKrishna.Elango@Sun.COM */ 2110187SKrishna.Elango@Sun.COM /* 2210187SKrishna.Elango@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2310187SKrishna.Elango@Sun.COM * Use is subject to license terms. 2410187SKrishna.Elango@Sun.COM */ 2510187SKrishna.Elango@Sun.COM 2610187SKrishna.Elango@Sun.COM /* SPARC specific code used by the pcieb driver */ 2710187SKrishna.Elango@Sun.COM 2810187SKrishna.Elango@Sun.COM #include <sys/types.h> 2910187SKrishna.Elango@Sun.COM #include <sys/ddi.h> 3010187SKrishna.Elango@Sun.COM #include <sys/kmem.h> 3110187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h> 3210187SKrishna.Elango@Sun.COM #include <sys/sunddi.h> 3310187SKrishna.Elango@Sun.COM #include <sys/sunndi.h> 3410187SKrishna.Elango@Sun.COM #include <sys/pcie.h> 3510187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h> 3610187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h> 3710187SKrishna.Elango@Sun.COM #include <io/pciex/pcieb.h> 3810187SKrishna.Elango@Sun.COM #include "pcieb_plx.h" 3910187SKrishna.Elango@Sun.COM 4010187SKrishna.Elango@Sun.COM /*LINTLIBRARY*/ 4110187SKrishna.Elango@Sun.COM 4210187SKrishna.Elango@Sun.COM /* PLX specific functions */ 4310187SKrishna.Elango@Sun.COM #ifdef PX_PLX 4410187SKrishna.Elango@Sun.COM static void plx_ro_disable(pcieb_devstate_t *pcieb); 4510187SKrishna.Elango@Sun.COM #ifdef PRINT_PLX_SEEPROM_CRC 4610187SKrishna.Elango@Sun.COM static void pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p); 4710187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */ 4810187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 4910187SKrishna.Elango@Sun.COM 5010187SKrishna.Elango@Sun.COM int 5110187SKrishna.Elango@Sun.COM pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 5210187SKrishna.Elango@Sun.COM void *arg, void *result) 5310187SKrishna.Elango@Sun.COM { 5410187SKrishna.Elango@Sun.COM return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 5510187SKrishna.Elango@Sun.COM } 5610187SKrishna.Elango@Sun.COM 5710187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 5810187SKrishna.Elango@Sun.COM void 5910187SKrishna.Elango@Sun.COM pcieb_plat_attach_workaround(dev_info_t *dip) 6010187SKrishna.Elango@Sun.COM { 6110187SKrishna.Elango@Sun.COM } 6210187SKrishna.Elango@Sun.COM 6310187SKrishna.Elango@Sun.COM int 6410187SKrishna.Elango@Sun.COM pcieb_plat_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 6510187SKrishna.Elango@Sun.COM ddi_intr_handle_impl_t *hdlp, void *result) 6610187SKrishna.Elango@Sun.COM { 6710187SKrishna.Elango@Sun.COM dev_info_t *cdip = rdip; 6810187SKrishna.Elango@Sun.COM pci_regspec_t *pci_rp; 6910187SKrishna.Elango@Sun.COM int reglen, len; 7010187SKrishna.Elango@Sun.COM uint32_t d, intr; 7110187SKrishna.Elango@Sun.COM 7210187SKrishna.Elango@Sun.COM if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || 7310187SKrishna.Elango@Sun.COM (hdlp->ih_type != DDI_INTR_TYPE_FIXED)) 7410187SKrishna.Elango@Sun.COM goto done; 7510187SKrishna.Elango@Sun.COM 7610187SKrishna.Elango@Sun.COM /* 7710187SKrishna.Elango@Sun.COM * If the interrupt-map property is defined at this 7810187SKrishna.Elango@Sun.COM * node, it will have performed the interrupt 7910187SKrishna.Elango@Sun.COM * translation as part of the property, so no 8010187SKrishna.Elango@Sun.COM * rotation needs to be done. 8110187SKrishna.Elango@Sun.COM */ 8210187SKrishna.Elango@Sun.COM if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 8310187SKrishna.Elango@Sun.COM "interrupt-map", &len) == DDI_PROP_SUCCESS) 8410187SKrishna.Elango@Sun.COM goto done; 8510187SKrishna.Elango@Sun.COM 8610187SKrishna.Elango@Sun.COM cdip = pcie_get_my_childs_dip(dip, rdip); 8710187SKrishna.Elango@Sun.COM 8810187SKrishna.Elango@Sun.COM /* 8910187SKrishna.Elango@Sun.COM * Use the devices reg property to determine its 9010187SKrishna.Elango@Sun.COM * PCI bus number and device number. 9110187SKrishna.Elango@Sun.COM */ 9210187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 9310187SKrishna.Elango@Sun.COM "reg", (caddr_t)&pci_rp, ®len) != DDI_SUCCESS) 9410187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 9510187SKrishna.Elango@Sun.COM 9610187SKrishna.Elango@Sun.COM intr = hdlp->ih_vector; 9710187SKrishna.Elango@Sun.COM 98*10923SEvan.Yan@Sun.COM d = (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED) ? 0 : 99*10923SEvan.Yan@Sun.COM PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); 100*10923SEvan.Yan@Sun.COM 10110187SKrishna.Elango@Sun.COM /* spin the interrupt */ 10210187SKrishna.Elango@Sun.COM if ((intr >= PCI_INTA) && (intr <= PCI_INTD)) 10310187SKrishna.Elango@Sun.COM hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1); 10410187SKrishna.Elango@Sun.COM else 10510187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range", 10610187SKrishna.Elango@Sun.COM ddi_driver_name(rdip), ddi_get_instance(rdip), 10710187SKrishna.Elango@Sun.COM ddi_driver_name(dip), intr); 10810187SKrishna.Elango@Sun.COM 10910187SKrishna.Elango@Sun.COM kmem_free(pci_rp, reglen); 11010187SKrishna.Elango@Sun.COM 11110187SKrishna.Elango@Sun.COM done: 11210187SKrishna.Elango@Sun.COM /* Pass up the request to our parent. */ 11310187SKrishna.Elango@Sun.COM return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)); 11410187SKrishna.Elango@Sun.COM } 11510187SKrishna.Elango@Sun.COM 11610187SKrishna.Elango@Sun.COM int 11710187SKrishna.Elango@Sun.COM pcieb_plat_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle) 11810187SKrishna.Elango@Sun.COM { 11910187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 12010187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_HOTPLUG, &cap_ptr)) != 12110187SKrishna.Elango@Sun.COM DDI_FAILURE) { 12210187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 12310187SKrishna.Elango@Sun.COM } 12410187SKrishna.Elango@Sun.COM 12510187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 12610187SKrishna.Elango@Sun.COM } 12710187SKrishna.Elango@Sun.COM 12810187SKrishna.Elango@Sun.COM /* 12910187SKrishna.Elango@Sun.COM * Disable PM on PLX. For PLX Transitioning one port on this switch to 13010187SKrishna.Elango@Sun.COM * low power causes links on other ports on the same station to die. 13110187SKrishna.Elango@Sun.COM * Due to PLX erratum #34, we can't allow the downstream device go to 13210187SKrishna.Elango@Sun.COM * non-D0 state. 13310187SKrishna.Elango@Sun.COM */ 13410187SKrishna.Elango@Sun.COM boolean_t 13510187SKrishna.Elango@Sun.COM pcieb_plat_pwr_disable(dev_info_t *dip) 13610187SKrishna.Elango@Sun.COM { 13710187SKrishna.Elango@Sun.COM uint16_t vendor_id = (PCIE_DIP2UPBUS(dip)->bus_dev_ven_id) & 0xFFFF; 13810187SKrishna.Elango@Sun.COM return (IS_PLX_VENDORID(vendor_id) ? B_TRUE : B_FALSE); 13910187SKrishna.Elango@Sun.COM } 14010187SKrishna.Elango@Sun.COM 14110187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 14210187SKrishna.Elango@Sun.COM boolean_t 14310187SKrishna.Elango@Sun.COM pcieb_plat_msi_supported(dev_info_t *dip) 14410187SKrishna.Elango@Sun.COM { 14510187SKrishna.Elango@Sun.COM return (B_TRUE); 14610187SKrishna.Elango@Sun.COM } 14710187SKrishna.Elango@Sun.COM 14810187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 14910187SKrishna.Elango@Sun.COM void 15010187SKrishna.Elango@Sun.COM pcieb_plat_intr_attach(pcieb_devstate_t *pcieb) 15110187SKrishna.Elango@Sun.COM { 15210187SKrishna.Elango@Sun.COM } 15310187SKrishna.Elango@Sun.COM 15410187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 15510187SKrishna.Elango@Sun.COM int 15610187SKrishna.Elango@Sun.COM pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg) 15710187SKrishna.Elango@Sun.COM { 15810187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 15910187SKrishna.Elango@Sun.COM } 16010187SKrishna.Elango@Sun.COM 16110187SKrishna.Elango@Sun.COM void 16210187SKrishna.Elango@Sun.COM pcieb_plat_initchild(dev_info_t *child) 16310187SKrishna.Elango@Sun.COM { 16410187SKrishna.Elango@Sun.COM intptr_t ppd = NULL; 16510187SKrishna.Elango@Sun.COM /* 16610187SKrishna.Elango@Sun.COM * XXX set ppd to 1 to disable iommu BDF protection on SPARC. 16710187SKrishna.Elango@Sun.COM * It relies on unused parent private data for PCI devices. 16810187SKrishna.Elango@Sun.COM */ 16910187SKrishna.Elango@Sun.COM if (ddi_prop_exists(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, 17010187SKrishna.Elango@Sun.COM "dvma-share")) 17110187SKrishna.Elango@Sun.COM ppd = 1; 17210187SKrishna.Elango@Sun.COM 17310187SKrishna.Elango@Sun.COM ddi_set_parent_data(child, (void *)ppd); 17410187SKrishna.Elango@Sun.COM } 17510187SKrishna.Elango@Sun.COM 17610187SKrishna.Elango@Sun.COM void 17710187SKrishna.Elango@Sun.COM pcieb_plat_uninitchild(dev_info_t *child) 17810187SKrishna.Elango@Sun.COM { 17910187SKrishna.Elango@Sun.COM /* 18010187SKrishna.Elango@Sun.COM * XXX Clear parent private data used as a flag to disable 18110187SKrishna.Elango@Sun.COM * iommu BDF protection 18210187SKrishna.Elango@Sun.COM */ 18310187SKrishna.Elango@Sun.COM if ((intptr_t)ddi_get_parent_data(child) == 1) 18410187SKrishna.Elango@Sun.COM ddi_set_parent_data(child, NULL); 18510187SKrishna.Elango@Sun.COM } 18610187SKrishna.Elango@Sun.COM 18710187SKrishna.Elango@Sun.COM #ifdef PX_PLX 18810187SKrishna.Elango@Sun.COM /* 18910187SKrishna.Elango@Sun.COM * These are PLX specific workarounds needed during attach. 19010187SKrishna.Elango@Sun.COM */ 19110187SKrishna.Elango@Sun.COM void 19210187SKrishna.Elango@Sun.COM pcieb_attach_plx_workarounds(pcieb_devstate_t *pcieb) 19310187SKrishna.Elango@Sun.COM { 19410187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb->pcieb_dip; 19510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 19610187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl; 19710187SKrishna.Elango@Sun.COM uint_t bus_num, primary, secondary; 19810187SKrishna.Elango@Sun.COM uint8_t dev_type = bus_p->bus_dev_type; 19910187SKrishna.Elango@Sun.COM uint16_t vendor_id = bus_p->bus_dev_ven_id & 0xFFFF; 200*10923SEvan.Yan@Sun.COM uint16_t device_id = bus_p->bus_dev_ven_id >> 16; 20110379SZachary.Kissel@Sun.COM int ce_mask = 0; 20210187SKrishna.Elango@Sun.COM 20310187SKrishna.Elango@Sun.COM if (!IS_PLX_VENDORID(vendor_id)) 20410187SKrishna.Elango@Sun.COM return; 20510187SKrishna.Elango@Sun.COM 206*10923SEvan.Yan@Sun.COM if ((device_id == PXB_DEVICE_PLX_8532) && 207*10923SEvan.Yan@Sun.COM (bus_p->bus_rev_id <= PXB_DEVICE_PLX_AA_REV)) 208*10923SEvan.Yan@Sun.COM /* Clear hotplug capability */ 209*10923SEvan.Yan@Sun.COM bus_p->bus_hp_sup_modes = PCIE_NONE_HP_MODE; 210*10923SEvan.Yan@Sun.COM 21110187SKrishna.Elango@Sun.COM /* 21210187SKrishna.Elango@Sun.COM * Due to a PLX HW bug we need to disable the receiver error CE on all 21310187SKrishna.Elango@Sun.COM * ports. To this end we create a property "pcie_ce_mask" with value 21410187SKrishna.Elango@Sun.COM * set to PCIE_AER_CE_RECEIVER_ERR. The pcie module will check for this 21510379SZachary.Kissel@Sun.COM * property before setting the AER CE mask. Be sure to honor all other 21610379SZachary.Kissel@Sun.COM * pcie_ce_mask settings. 21710187SKrishna.Elango@Sun.COM */ 21810379SZachary.Kissel@Sun.COM ce_mask = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 21910379SZachary.Kissel@Sun.COM "pcie_ce_mask", 0); 22010187SKrishna.Elango@Sun.COM (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 22110379SZachary.Kissel@Sun.COM "pcie_ce_mask", (PCIE_AER_CE_RECEIVER_ERR|ce_mask)); 22210187SKrishna.Elango@Sun.COM 22310187SKrishna.Elango@Sun.COM /* 22410187SKrishna.Elango@Sun.COM * There is a bug in the PLX 8114 bridge, such that an 8-bit 22510187SKrishna.Elango@Sun.COM * write to the secondary bus number register will corrupt an 22610187SKrishna.Elango@Sun.COM * internal shadow copy of the primary bus number. Reading 22710187SKrishna.Elango@Sun.COM * out the registers and writing the same values back as 22810187SKrishna.Elango@Sun.COM * 16-bits resolves the problem. This bug was reported by 22910187SKrishna.Elango@Sun.COM * PLX as errata #19. 23010187SKrishna.Elango@Sun.COM */ 23110187SKrishna.Elango@Sun.COM primary = pci_config_get8(config_handle, PCI_BCNF_PRIBUS); 23210187SKrishna.Elango@Sun.COM secondary = pci_config_get8(config_handle, PCI_BCNF_SECBUS); 23310187SKrishna.Elango@Sun.COM bus_num = (secondary << 8) | primary; 23410187SKrishna.Elango@Sun.COM pci_config_put16(config_handle, PCI_BCNF_PRIBUS, bus_num); 23510187SKrishna.Elango@Sun.COM 23610187SKrishna.Elango@Sun.COM /* 23710187SKrishna.Elango@Sun.COM * Workaround for a race condition between hotplug 23810187SKrishna.Elango@Sun.COM * initialization and actual MSI interrupt registration 23910187SKrishna.Elango@Sun.COM * for hotplug functionality. The hotplug initialization 24010187SKrishna.Elango@Sun.COM * generates an INTx interrupt for hotplug events and this 24110187SKrishna.Elango@Sun.COM * INTx interrupt may interfere with shared leaf drivers 24210187SKrishna.Elango@Sun.COM * using same INTx interrupt, which may eventually block 24310187SKrishna.Elango@Sun.COM * the leaf drivers. 24410187SKrishna.Elango@Sun.COM */ 24510187SKrishna.Elango@Sun.COM if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) || 24610187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) || 24710187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) || 24810187SKrishna.Elango@Sun.COM (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) { 24910187SKrishna.Elango@Sun.COM pci_config_put16(config_handle, PCI_CONF_COMM, 25010187SKrishna.Elango@Sun.COM pci_config_get16(config_handle, PCI_CONF_COMM) | 25110187SKrishna.Elango@Sun.COM PCI_COMM_INTX_DISABLE); 25210187SKrishna.Elango@Sun.COM } 25310187SKrishna.Elango@Sun.COM 25410187SKrishna.Elango@Sun.COM /* 25510187SKrishna.Elango@Sun.COM * Disable PLX Special Relaxed Ordering 25610187SKrishna.Elango@Sun.COM */ 25710187SKrishna.Elango@Sun.COM plx_ro_disable(pcieb); 25810187SKrishna.Elango@Sun.COM 25910187SKrishna.Elango@Sun.COM #ifdef PRINT_PLX_SEEPROM_CRC 26010187SKrishna.Elango@Sun.COM /* check seeprom CRC to ensure the platform config is right */ 26110187SKrishna.Elango@Sun.COM (void) pcieb_print_plx_seeprom_crc_data(pcieb); 26210187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */ 26310187SKrishna.Elango@Sun.COM } 26410187SKrishna.Elango@Sun.COM 26510187SKrishna.Elango@Sun.COM /* 26610187SKrishna.Elango@Sun.COM * These are PLX specific workarounds called during child's initchild. 26710187SKrishna.Elango@Sun.COM */ 26810187SKrishna.Elango@Sun.COM int 26910187SKrishna.Elango@Sun.COM pcieb_init_plx_workarounds(pcieb_devstate_t *pcieb, dev_info_t *child) 27010187SKrishna.Elango@Sun.COM { 27110187SKrishna.Elango@Sun.COM int i; 27210187SKrishna.Elango@Sun.COM int result = DDI_FAILURE; 27310187SKrishna.Elango@Sun.COM uint16_t reg = 0; 27410187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 27510187SKrishna.Elango@Sun.COM uint16_t vendor_id = 27610187SKrishna.Elango@Sun.COM (PCIE_DIP2UPBUS(pcieb->pcieb_dip))->bus_dev_ven_id & 0xFFFF; 27710187SKrishna.Elango@Sun.COM 27810187SKrishna.Elango@Sun.COM if (!IS_PLX_VENDORID(vendor_id)) 27910187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 28010187SKrishna.Elango@Sun.COM 28110187SKrishna.Elango@Sun.COM /* 28210187SKrishna.Elango@Sun.COM * Due to a PLX HW bug, a SW workaround to prevent the chip from 28310187SKrishna.Elango@Sun.COM * wedging is needed. SW just needs to tranfer 64 TLPs from 28410187SKrishna.Elango@Sun.COM * the downstream port to the child device. 28510187SKrishna.Elango@Sun.COM * The most benign way of doing this is to read the ID register 28610187SKrishna.Elango@Sun.COM * 64 times. This SW workaround should have minimum performance 28710187SKrishna.Elango@Sun.COM * impact and shouldn't cause a problem for all other bridges 28810187SKrishna.Elango@Sun.COM * and switches. 28910187SKrishna.Elango@Sun.COM * 29010187SKrishna.Elango@Sun.COM * The code needs to be written in a way to make sure it isn't 29110187SKrishna.Elango@Sun.COM * optimized out. 29210187SKrishna.Elango@Sun.COM */ 29310187SKrishna.Elango@Sun.COM if (!pxb_tlp_count) { 29410187SKrishna.Elango@Sun.COM result = DDI_SUCCESS; 29510187SKrishna.Elango@Sun.COM goto done; 29610187SKrishna.Elango@Sun.COM } 29710187SKrishna.Elango@Sun.COM 29810187SKrishna.Elango@Sun.COM if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { 29910187SKrishna.Elango@Sun.COM result = DDI_FAILURE; 30010187SKrishna.Elango@Sun.COM goto done; 30110187SKrishna.Elango@Sun.COM } 30210187SKrishna.Elango@Sun.COM 30310187SKrishna.Elango@Sun.COM for (i = 0; i < pxb_tlp_count; i += 1) 30410187SKrishna.Elango@Sun.COM reg |= pci_config_get16(config_handle, PCI_CONF_VENID); 30510187SKrishna.Elango@Sun.COM 30610187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(pcieb->pcieb_dip))) 30710187SKrishna.Elango@Sun.COM pcieb_set_pci_perf_parameters(child, config_handle); 30810187SKrishna.Elango@Sun.COM 30910187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 31010187SKrishna.Elango@Sun.COM result = DDI_SUCCESS; 31110187SKrishna.Elango@Sun.COM done: 31210187SKrishna.Elango@Sun.COM return (result); 31310187SKrishna.Elango@Sun.COM } 31410187SKrishna.Elango@Sun.COM 31510187SKrishna.Elango@Sun.COM /* 31610187SKrishna.Elango@Sun.COM * Disable PLX specific relaxed ordering mode. Due to PLX 31710187SKrishna.Elango@Sun.COM * erratum #6, use of this mode with Cut-Through Cancellation 31810187SKrishna.Elango@Sun.COM * can result in dropped Completion type packets. 31910187SKrishna.Elango@Sun.COM * 32010187SKrishna.Elango@Sun.COM * Clear the Relaxed Ordering Mode on 8533 and 8548 switches. 32110187SKrishna.Elango@Sun.COM * To disable RO, clear bit 5 in offset 0x664, an undocumented 32210187SKrishna.Elango@Sun.COM * bit in the PLX spec, on Ports 0, 8 and 12. Proprietary PLX 32310187SKrishna.Elango@Sun.COM * registers are normally accessible only via memspace from Port 32410187SKrishna.Elango@Sun.COM * 0. If port 0 is attached go ahead and disable RO on Port 0, 32510187SKrishna.Elango@Sun.COM * 8 and 12, if they exist. 32610187SKrishna.Elango@Sun.COM */ 32710187SKrishna.Elango@Sun.COM static void 32810187SKrishna.Elango@Sun.COM plx_ro_disable(pcieb_devstate_t *pcieb) 32910187SKrishna.Elango@Sun.COM { 33010187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip); 33110187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb->pcieb_dip; 33210187SKrishna.Elango@Sun.COM uint16_t device_id = bus_p->bus_dev_ven_id >> 16; 33310187SKrishna.Elango@Sun.COM pci_regspec_t *reg_spec, *addr_spec; 33410187SKrishna.Elango@Sun.COM int rlen, alen; 33510187SKrishna.Elango@Sun.COM int orig_rsize, new_rsize; 33610187SKrishna.Elango@Sun.COM uint_t rnum, anum; 33710187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t attr; 33810187SKrishna.Elango@Sun.COM ddi_acc_handle_t hdl; 33910187SKrishna.Elango@Sun.COM caddr_t regsp; 34010187SKrishna.Elango@Sun.COM uint32_t val, port_enable; 34110187SKrishna.Elango@Sun.COM char *offset; 34210187SKrishna.Elango@Sun.COM char *port_offset; 34310187SKrishna.Elango@Sun.COM 34410187SKrishna.Elango@Sun.COM if (!((device_id == PXB_DEVICE_PLX_8533) || 34510187SKrishna.Elango@Sun.COM (device_id == PXB_DEVICE_PLX_8548))) 34610187SKrishna.Elango@Sun.COM return; 34710187SKrishna.Elango@Sun.COM 34810187SKrishna.Elango@Sun.COM /* You can also only do this on Port 0 */ 34910187SKrishna.Elango@Sun.COM val = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP); 35010187SKrishna.Elango@Sun.COM val = (val >> PCIE_LINKCAP_PORT_NUMBER_SHIFT) & 35110187SKrishna.Elango@Sun.COM PCIE_LINKCAP_PORT_NUMBER_MASK; 35210187SKrishna.Elango@Sun.COM 35310187SKrishna.Elango@Sun.COM PCIEB_DEBUG(DBG_ATTACH, dip, "PLX RO Disable : bdf=0x%x port=%d\n", 35410187SKrishna.Elango@Sun.COM bus_p->bus_bdf, val); 35510187SKrishna.Elango@Sun.COM 35610187SKrishna.Elango@Sun.COM if (val != 0) 35710187SKrishna.Elango@Sun.COM return; 35810187SKrishna.Elango@Sun.COM 35910187SKrishna.Elango@Sun.COM /* 36010187SKrishna.Elango@Sun.COM * Read the reg property, but allocate extra space incase we need to add 36110187SKrishna.Elango@Sun.COM * a new entry later. 36210187SKrishna.Elango@Sun.COM */ 36310187SKrishna.Elango@Sun.COM if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 36410187SKrishna.Elango@Sun.COM &orig_rsize) != DDI_SUCCESS) 36510187SKrishna.Elango@Sun.COM return; 36610187SKrishna.Elango@Sun.COM 36710187SKrishna.Elango@Sun.COM new_rsize = orig_rsize + sizeof (pci_regspec_t); 36810187SKrishna.Elango@Sun.COM reg_spec = kmem_alloc(new_rsize, KM_SLEEP); 36910187SKrishna.Elango@Sun.COM 37010187SKrishna.Elango@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 37110187SKrishna.Elango@Sun.COM (caddr_t)reg_spec, &orig_rsize) != DDI_SUCCESS) 37210187SKrishna.Elango@Sun.COM goto fail; 37310187SKrishna.Elango@Sun.COM 37410187SKrishna.Elango@Sun.COM /* Find the mem32 reg property */ 37510187SKrishna.Elango@Sun.COM rlen = orig_rsize / sizeof (pci_regspec_t); 37610187SKrishna.Elango@Sun.COM for (rnum = 0; rnum < rlen; rnum++) { 37710187SKrishna.Elango@Sun.COM if ((reg_spec[rnum].pci_phys_hi & PCI_ADDR_MASK) == 37810187SKrishna.Elango@Sun.COM PCI_ADDR_MEM32) 37910187SKrishna.Elango@Sun.COM goto fix; 38010187SKrishna.Elango@Sun.COM } 38110187SKrishna.Elango@Sun.COM 38210187SKrishna.Elango@Sun.COM /* 38310187SKrishna.Elango@Sun.COM * Mem32 reg property was not found. 38410187SKrishna.Elango@Sun.COM * Look for it in assign-address property. 38510187SKrishna.Elango@Sun.COM */ 38610187SKrishna.Elango@Sun.COM addr_spec = bus_p->bus_assigned_addr; 38710187SKrishna.Elango@Sun.COM alen = bus_p->bus_assigned_entries; 38810187SKrishna.Elango@Sun.COM for (anum = 0; anum < alen; anum++) { 38910187SKrishna.Elango@Sun.COM if ((addr_spec[anum].pci_phys_hi & PCI_ADDR_MASK) == 39010187SKrishna.Elango@Sun.COM PCI_ADDR_MEM32) 39110187SKrishna.Elango@Sun.COM goto update; 39210187SKrishna.Elango@Sun.COM } 39310187SKrishna.Elango@Sun.COM 39410187SKrishna.Elango@Sun.COM /* Unable to find mem space assigned address, give up. */ 39510187SKrishna.Elango@Sun.COM goto fail; 39610187SKrishna.Elango@Sun.COM 39710187SKrishna.Elango@Sun.COM update: 39810187SKrishna.Elango@Sun.COM /* 39910187SKrishna.Elango@Sun.COM * Add the mem32 access to the reg spec. 40010187SKrishna.Elango@Sun.COM * Use the last entry which was previously allocated. 40110187SKrishna.Elango@Sun.COM */ 40210187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_phys_hi = (addr_spec[anum].pci_phys_hi & 40310187SKrishna.Elango@Sun.COM ~PCI_REG_REL_M); 40410187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_phys_mid = 0; 40510187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_phys_low = 0; 40610187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_size_hi = addr_spec[anum].pci_size_hi; 40710187SKrishna.Elango@Sun.COM reg_spec[rnum].pci_size_low = addr_spec[anum].pci_size_low; 40810187SKrishna.Elango@Sun.COM 40910187SKrishna.Elango@Sun.COM /* Create the new reg_spec data and update the property */ 41010187SKrishna.Elango@Sun.COM if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", 41110187SKrishna.Elango@Sun.COM (int *)reg_spec, (new_rsize / sizeof (int))) != DDI_SUCCESS) 41210187SKrishna.Elango@Sun.COM goto fail; 41310187SKrishna.Elango@Sun.COM 41410187SKrishna.Elango@Sun.COM fix: 41510187SKrishna.Elango@Sun.COM attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 41610187SKrishna.Elango@Sun.COM attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 41710187SKrishna.Elango@Sun.COM attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 41810187SKrishna.Elango@Sun.COM 41910187SKrishna.Elango@Sun.COM if (ddi_regs_map_setup(dip, rnum, ®sp, 0, 0, &attr, 42010187SKrishna.Elango@Sun.COM &hdl) != DDI_SUCCESS) 42110187SKrishna.Elango@Sun.COM goto fail; 42210187SKrishna.Elango@Sun.COM 42310187SKrishna.Elango@Sun.COM /* Grab register which shows which ports are enabled */ 42410187SKrishna.Elango@Sun.COM offset = (char *)regsp + PLX_INGRESS_PORT_ENABLE; 42510187SKrishna.Elango@Sun.COM port_enable = ddi_get32(hdl, (uint32_t *)offset); 42610187SKrishna.Elango@Sun.COM 42710187SKrishna.Elango@Sun.COM if ((port_enable == 0xFFFFFFFF) || (port_enable == 0)) 42810187SKrishna.Elango@Sun.COM goto done; 42910187SKrishna.Elango@Sun.COM 43010187SKrishna.Elango@Sun.COM offset = (char *)regsp + PLX_INGRESS_CONTROL_SHADOW; 43110187SKrishna.Elango@Sun.COM 43210187SKrishna.Elango@Sun.COM /* Disable RO on Port 0 */ 43310187SKrishna.Elango@Sun.COM port_offset = 0x0 + offset; 43410187SKrishna.Elango@Sun.COM val = ddi_get32(hdl, (uint32_t *)port_offset); 43510187SKrishna.Elango@Sun.COM if (val & PLX_RO_MODE_BIT) 43610187SKrishna.Elango@Sun.COM val ^= PLX_RO_MODE_BIT; 43710187SKrishna.Elango@Sun.COM ddi_put32(hdl, (uint32_t *)port_offset, val); 43810187SKrishna.Elango@Sun.COM 43910187SKrishna.Elango@Sun.COM /* Disable RO on Port 8, but make sure its enabled */ 44010187SKrishna.Elango@Sun.COM if (!(port_enable & (1 << 8))) 44110187SKrishna.Elango@Sun.COM goto port12; 44210187SKrishna.Elango@Sun.COM 44310187SKrishna.Elango@Sun.COM port_offset = (8 * 0x1000) + offset; 44410187SKrishna.Elango@Sun.COM val = ddi_get32(hdl, (uint32_t *)port_offset); 44510187SKrishna.Elango@Sun.COM if (val & PLX_RO_MODE_BIT) 44610187SKrishna.Elango@Sun.COM val ^= PLX_RO_MODE_BIT; 44710187SKrishna.Elango@Sun.COM ddi_put32(hdl, (uint32_t *)port_offset, val); 44810187SKrishna.Elango@Sun.COM 44910187SKrishna.Elango@Sun.COM port12: 45010187SKrishna.Elango@Sun.COM /* Disable RO on Port 12, but make sure it exists */ 45110187SKrishna.Elango@Sun.COM if (!(port_enable & (1 << 12))) 45210187SKrishna.Elango@Sun.COM goto done; 45310187SKrishna.Elango@Sun.COM 45410187SKrishna.Elango@Sun.COM port_offset = (12 * 0x1000) + offset; 45510187SKrishna.Elango@Sun.COM val = ddi_get32(hdl, (uint32_t *)port_offset); 45610187SKrishna.Elango@Sun.COM if (val & PLX_RO_MODE_BIT) 45710187SKrishna.Elango@Sun.COM val ^= PLX_RO_MODE_BIT; 45810187SKrishna.Elango@Sun.COM ddi_put32(hdl, (uint32_t *)port_offset, val); 45910187SKrishna.Elango@Sun.COM 46010187SKrishna.Elango@Sun.COM goto done; 46110187SKrishna.Elango@Sun.COM 46210187SKrishna.Elango@Sun.COM done: 46310187SKrishna.Elango@Sun.COM ddi_regs_map_free(&hdl); 46410187SKrishna.Elango@Sun.COM fail: 46510187SKrishna.Elango@Sun.COM kmem_free(reg_spec, new_rsize); 46610187SKrishna.Elango@Sun.COM } 46710187SKrishna.Elango@Sun.COM 46810187SKrishna.Elango@Sun.COM #ifdef PRINT_PLX_SEEPROM_CRC 46910187SKrishna.Elango@Sun.COM static void 47010187SKrishna.Elango@Sun.COM pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p) 47110187SKrishna.Elango@Sun.COM { 47210187SKrishna.Elango@Sun.COM ddi_acc_handle_t h; 47310187SKrishna.Elango@Sun.COM dev_info_t *dip = pcieb_p->pcieb_dip; 47410187SKrishna.Elango@Sun.COM uint16_t vendorid = (PCIE_DIP2BUS(dip)->bus_dev_ven_id) & 0xFFFF; 47510187SKrishna.Elango@Sun.COM int nregs; 47610187SKrishna.Elango@Sun.COM caddr_t mp; 47710187SKrishna.Elango@Sun.COM off_t bar_size; 47810187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t mattr = { 47910187SKrishna.Elango@Sun.COM DDI_DEVICE_ATTR_V0, 48010187SKrishna.Elango@Sun.COM DDI_STRUCTURE_LE_ACC, 48110187SKrishna.Elango@Sun.COM DDI_STRICTORDER_ACC 48210187SKrishna.Elango@Sun.COM }; 48310187SKrishna.Elango@Sun.COM uint32_t addr_reg_off = 0x260, data_reg_off = 0x264, data = 0x6BE4; 48410187SKrishna.Elango@Sun.COM 48510187SKrishna.Elango@Sun.COM if (vendorid != PXB_VENDOR_PLX) 48610187SKrishna.Elango@Sun.COM return; 48710187SKrishna.Elango@Sun.COM if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) 48810187SKrishna.Elango@Sun.COM return; 48910187SKrishna.Elango@Sun.COM if (nregs < 2) /* check for CONF entry only, no BARs */ 49010187SKrishna.Elango@Sun.COM return; 49110187SKrishna.Elango@Sun.COM if (ddi_dev_regsize(dip, 1, &bar_size) != DDI_SUCCESS) 49210187SKrishna.Elango@Sun.COM return; 49310187SKrishna.Elango@Sun.COM if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mp, 0, bar_size, 49410187SKrishna.Elango@Sun.COM &mattr, &h) != DDI_SUCCESS) 49510187SKrishna.Elango@Sun.COM return; 49610187SKrishna.Elango@Sun.COM ddi_put32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off), data); 49710187SKrishna.Elango@Sun.COM delay(drv_usectohz(1000000)); 49810187SKrishna.Elango@Sun.COM printf("%s#%d: EEPROM StatusReg = %x, CRC = %x\n", 49910187SKrishna.Elango@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), 50010187SKrishna.Elango@Sun.COM ddi_get32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off)), 50110187SKrishna.Elango@Sun.COM ddi_get32(h, (uint32_t *)((uchar_t *)mp + data_reg_off))); 50210187SKrishna.Elango@Sun.COM #ifdef PLX_HOT_RESET_DISABLE 50310187SKrishna.Elango@Sun.COM /* prevent hot reset from propogating downstream. */ 50410187SKrishna.Elango@Sun.COM data = ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC)); 50510187SKrishna.Elango@Sun.COM ddi_put32(h, (uint32_t *)((uchar_t *)mp + 0x1DC), data | 0x80000); 50610187SKrishna.Elango@Sun.COM delay(drv_usectohz(1000000)); 50710187SKrishna.Elango@Sun.COM printf("%s#%d: EEPROM 0x1DC prewrite=%x postwrite=%x\n", 50810187SKrishna.Elango@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), data, 50910187SKrishna.Elango@Sun.COM ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC))); 51010187SKrishna.Elango@Sun.COM #endif /* PLX_HOT_RESET_DISABLE */ 51110187SKrishna.Elango@Sun.COM ddi_regs_map_free(&h); 51210187SKrishna.Elango@Sun.COM } 51310187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */ 51410187SKrishna.Elango@Sun.COM #endif /* PX_PLX */ 515