/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* SPARC specific code used by the pcieb driver */
#include <sys/sysmacros.h>
#include <sys/pcie_impl.h>
#include "pcieb_plx.h"
/*LINTLIBRARY*/
/* PLX specific functions */
#ifdef PX_PLX
#ifdef PRINT_PLX_SEEPROM_CRC
#endif /* PRINT_PLX_SEEPROM_CRC */
#endif /* PX_PLX */
int
{
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
void
{
}
int
{
if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) ||
goto done;
/*
* If the interrupt-map property is defined at this
* node, it will have performed the interrupt
* translation as part of the property, so no
* rotation needs to be done.
*/
goto done;
/*
* Use the devices reg property to determine its
* PCI bus number and device number.
*/
return (DDI_FAILURE);
/* spin the interrupt */
else
done:
/* Pass up the request to our parent. */
}
int
{
DDI_FAILURE) {
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/*
* Disable PM on PLX. For PLX Transitioning one port on this switch to
* low power causes links on other ports on the same station to die.
* Due to PLX erratum #34, we can't allow the downstream device go to
* non-D0 state.
*/
{
}
/*ARGSUSED*/
{
return (B_TRUE);
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
int
{
return (DDI_SUCCESS);
}
void
{
/*
* XXX set ppd to 1 to disable iommu BDF protection on SPARC.
* It relies on unused parent private data for PCI devices.
*/
"dvma-share"))
ppd = 1;
}
void
{
/*
* XXX Clear parent private data used as a flag to disable
* iommu BDF protection
*/
}
#ifdef PX_PLX
/*
* These are PLX specific workarounds needed during attach.
*/
void
{
int ce_mask = 0;
if (!IS_PLX_VENDORID(vendor_id))
return;
if ((device_id == PXB_DEVICE_PLX_8532) &&
/* Clear hotplug capability */
/*
* Due to a PLX HW bug we need to disable the receiver error CE on all
* ports. To this end we create a property "pcie_ce_mask" with value
* set to PCIE_AER_CE_RECEIVER_ERR. The pcie module will check for this
* property before setting the AER CE mask. Be sure to honor all other
* pcie_ce_mask settings.
*/
"pcie_ce_mask", 0);
/*
* There is a bug in the PLX 8114 bridge, such that an 8-bit
* write to the secondary bus number register will corrupt an
* internal shadow copy of the primary bus number. Reading
* out the registers and writing the same values back as
* 16-bits resolves the problem. This bug was reported by
* PLX as errata #19.
*/
/*
* Workaround for a race condition between hotplug
* initialization and actual MSI interrupt registration
* for hotplug functionality. The hotplug initialization
* generates an INTx interrupt for hotplug events and this
* INTx interrupt may interfere with shared leaf drivers
* using same INTx interrupt, which may eventually block
* the leaf drivers.
*/
if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
(dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
}
/*
* Disable PLX Special Relaxed Ordering
*/
#ifdef PRINT_PLX_SEEPROM_CRC
/* check seeprom CRC to ensure the platform config is right */
(void) pcieb_print_plx_seeprom_crc_data(pcieb);
#endif /* PRINT_PLX_SEEPROM_CRC */
}
/*
* These are PLX specific workarounds called during child's initchild.
*/
int
{
int i;
if (!IS_PLX_VENDORID(vendor_id))
return (DDI_SUCCESS);
/*
* Due to a PLX HW bug, a SW workaround to prevent the chip from
* wedging is needed. SW just needs to tranfer 64 TLPs from
* the downstream port to the child device.
* The most benign way of doing this is to read the ID register
* 64 times. This SW workaround should have minimum performance
* impact and shouldn't cause a problem for all other bridges
* and switches.
*
* The code needs to be written in a way to make sure it isn't
* optimized out.
*/
if (!pxb_tlp_count) {
goto done;
}
goto done;
}
for (i = 0; i < pxb_tlp_count; i += 1)
done:
return (result);
}
/*
* Disable PLX specific relaxed ordering mode. Due to PLX
* erratum #6, use of this mode with Cut-Through Cancellation
* can result in dropped Completion type packets.
*
* Clear the Relaxed Ordering Mode on 8533 and 8548 switches.
* To disable RO, clear bit 5 in offset 0x664, an undocumented
* bit in the PLX spec, on Ports 0, 8 and 12. Proprietary PLX
* registers are normally accessible only via memspace from Port
* 0. If port 0 is attached go ahead and disable RO on Port 0,
* 8 and 12, if they exist.
*/
static void
{
char *offset;
char *port_offset;
if (!((device_id == PXB_DEVICE_PLX_8533) ||
(device_id == PXB_DEVICE_PLX_8548)))
return;
/* You can also only do this on Port 0 */
if (val != 0)
return;
/*
* Read the reg property, but allocate extra space incase we need to add
* a new entry later.
*/
&orig_rsize) != DDI_SUCCESS)
return;
goto fail;
/* Find the mem32 reg property */
goto fix;
}
/*
* Mem32 reg property was not found.
* Look for it in assign-address property.
*/
goto update;
}
/* Unable to find mem space assigned address, give up. */
goto fail;
/*
* Add the mem32 access to the reg spec.
* Use the last entry which was previously allocated.
*/
/* Create the new reg_spec data and update the property */
goto fail;
fix:
&hdl) != DDI_SUCCESS)
goto fail;
/* Grab register which shows which ports are enabled */
goto done;
/* Disable RO on Port 0 */
if (val & PLX_RO_MODE_BIT)
val ^= PLX_RO_MODE_BIT;
/* Disable RO on Port 8, but make sure its enabled */
goto port12;
if (val & PLX_RO_MODE_BIT)
val ^= PLX_RO_MODE_BIT;
/* Disable RO on Port 12, but make sure it exists */
goto done;
if (val & PLX_RO_MODE_BIT)
val ^= PLX_RO_MODE_BIT;
goto done;
done:
fail:
}
#ifdef PRINT_PLX_SEEPROM_CRC
static void
{
int nregs;
};
if (vendorid != PXB_VENDOR_PLX)
return;
return;
return;
return;
&mattr, &h) != DDI_SUCCESS)
return;
printf("%s#%d: EEPROM StatusReg = %x, CRC = %x\n",
#ifdef PLX_HOT_RESET_DISABLE
/* prevent hot reset from propogating downstream. */
printf("%s#%d: EEPROM 0x1DC prewrite=%x postwrite=%x\n",
#endif /* PLX_HOT_RESET_DISABLE */
ddi_regs_map_free(&h);
}
#endif /* PRINT_PLX_SEEPROM_CRC */
#endif /* PX_PLX */