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