px_fm.c revision 1ff6511282dda236fdea133a0fc53438d8c4f5fd
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* PX Fault Management Architecture
*/
#include "px_obj.h"
#define PX_PCIE_PANIC_BITS \
#define PX_PCIE_NO_PANIC_BITS \
#if defined(DEBUG)
#else /* DEBUG */
#define px_pcie_log 0 &&
#endif /* DEBUG */
/* external functions */
/*
* Initialize px FMA support
*/
int
{
/*
* Initialize pci_target_queue for FMA handling of
* pci errors.
*/
/*
* check parents' capability
*/
/*
* parents need to be ereport and error handling capable
*/
/*
* Initialize lock to synchronize fabric error handling
*/
/*
* register error callback in parent
*/
return (DDI_SUCCESS);
}
/*
* Deregister FMA
*/
void
{
}
/*
* Function used to setup access functions depending on level of desired
* protection.
*/
void
{
switch (fflag) {
case DDI_FLAGERR_ACC:
break;
case DDI_CAUTIOUS_ACC :
break;
default:
break;
}
}
}
/*
* Function used to initialize FMA for our children nodes. Called
* through pci busops when child node calls ddi_fm_init.
*/
/*ARGSUSED*/
int
{
}
/*
* lock access for exclusive PCIe access
*/
void
{
/*
* Both utilize i_ddi_ontrap which, on sparcv9, implements
* similar protection as what on_trap() does, and which calls
* membar #Sync to flush out all cpu deferred errors
* membar #Sync - a difference from what's in pci_bus_enter().
*/
}
/*
* unlock access for exclusive PCIe access
*/
/* ARGSUSED */
void
{
}
/*
* PCI error callback which is registered with our parent to call
* for PCIe logging when the CPU traps due to PCIe Uncorrectable Errors
*/
/*ARGSUSED*/
int
{
int i, acc_type = 0;
int range_len;
/*
* If the current thread already owns the px_fm_mutex, then we
* have encountered an error while processing a previous
* error. Attempting to take the mutex again will cause the
* system to deadlock.
*/
return (DDI_FM_FATAL);
/*
* Make sure this failed load came from this PCIe port. Check by
* matching the upper 32 bits of the address with the ranges property.
*/
i = 0;
case PCI_ADDR_CONFIG:
break;
case PCI_ADDR_IO:
break;
case PCI_ADDR_MEM32:
break;
}
break;
}
}
/* This address doesn't belong to this leaf, just return with OK */
if (!acc_type) {
return (DDI_FM_OK);
} else if (acc_type == PF_IO_ADDR) {
return (DDI_FM_FATAL);
}
if (!px_lib_is_in_drain_state(px_p)) {
/*
* This is to ensure that device corresponding to the addr of
*/
&px_p->px_dq_tail);
}
(lookup == PF_HDL_NOTFOUND))
return (DDI_FM_FATAL);
return (DDI_FM_OK);
return (DDI_FM_NONFATAL);
}
/*
* px_err_fabric_intr:
* Interrupt handler for PCIE fabric block.
* o lock
* o create derr
* o px_err_cmn_intr(leaf, with jbc)
* o send ereport(fire fmri, derr, payload = BDF)
* o dispatch (leaf)
* o unlock
* o handle error: fatal? fm_panic() : return INTR_CLAIMED)
*/
/* ARGSUSED */
{
/* Create the derr */
/* Ensure that the rid of the fabric message will get scanned. */
/* call rootport dispatch */
if (!px_lib_is_in_drain_state(px_p)) {
&px_p->px_dq_tail);
}
return (DDI_INTR_CLAIMED);
}
/*
* px_err_safeacc_check:
* done on a particular leaf.
*
* Safe access reads induced fire errors will be handled by cpu trap handler
* which will call px_fm_callback() which calls this function. In that
* case, the derr fields will be set by trap handler with the correct values.
*
* Safe access writes induced errors will be handled by px interrupt
* handlers, this function will fill in the derr fields.
*
* If a cpu trap does occur, it will quiesce all other interrupts allowing
* the cpu trap error handling to finish before Fire receives an interrupt.
*
* If fire does indeed have an error when a cpu trap occurs as a result of
* In which case derr will be initialized as "UNEXPECTED" by the interrupt
* handler and this function will need to find if this error occured in the
* middle of a safe access operation.
*
* @param px_p leaf in which to check access
* @param derr fm err data structure to be updated
*/
void
{
return;
}
/* safe access checking */
switch (acctype) {
case DDI_FM_ERR_EXPECTED:
/*
* cautious access protection, protected from all err.
*/
break;
case DDI_FM_ERR_POKE:
/*
* ddi_poke protection, check nexus and children for
* expected errors.
*/
membar_sync();
break;
case DDI_FM_ERR_PEEK:
break;
}
}
/*
* Suggest panic if any EQ (except CE q) has overflown.
*/
int
{
int i;
for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
continue;
return (PX_PANIC);
}
return (PX_NO_PANIC);
}
static void
{
pcie_req_id_t fault_bdf = 0;
uint32_t fault_addr = 0;
/*
* set RC s_status in PCI term to coordinate with downstream fabric
* errors ananlysis.
*/
}
}
int
{
int err = PX_NO_ERROR;
if (ce_reg)
if (!ue_reg)
goto done;
if (ue_reg & PCIE_AER_UCE_PTLP)
if (ue_reg & PX_PCIE_PANIC_BITS)
if (ue_reg & PX_PCIE_NO_PANIC_BITS)
err |= PX_NO_PANIC;
/* Scan the fabric to clean up error bits, for the following errors. */
done:
return (err);
}
#if defined(DEBUG)
static void
{
"A PCIe RC error has occured with a severity of \"%s\"\n"
"\tCE: 0x%x UE: 0x%x Primary UE: 0x%x\n"
"\tTX Hdr: 0x%x 0x%x 0x%x 0x%x\n\tRX Hdr: 0x%x 0x%x 0x%x 0x%x\n",
}
#endif /* DEBUG */
/*
* handle lookup.
*/
static int
{
int sts = PF_HDL_NOTFOUND;
return (PX_PANIC);
goto done;
if (tlp_sts == DDI_FAILURE)
goto done;
switch (tlp_cmd) {
case PCIE_TLP_TYPE_CPL:
case PCIE_TLP_TYPE_CPLLK:
/*
* Usually a PTLP is a CPL with data. Grab the completer BDF
* from the RX TLP, and the original address from the TX TLP.
*/
&trans_type);
} /* FALLTHRU */
case PCIE_TLP_TYPE_IO:
case PCIE_TLP_TYPE_MEM:
case PCIE_TLP_TYPE_MEMLK:
break;
default:
}
done:
}
/*
* This function appends a pf_data structure to the error q which is used later
* during PCIe fabric scan. It signifies:
*
* fault_bdf: The bdf that caused the fault, which may have error bits set.
* fault_addr: The PIO addr that caused the fault, such as failed PIO, but not
* failed DMAs.
* s_status: Secondary Status equivalent to why the fault occured.
* Either the fault bdf or addr may be NULL, but not both.
*/
int px_foo = 0;
void
{
if (!fault_bdf && !fault_addr)
return;
if (px_foo) {
px_foo = 0;
} else
}
/*
* Panic if the err tunable is set and that we are not already in the middle
* of panic'ing.
*/
void
{
int ferr = PX_NO_ERROR;
if (panicstr)
return;
goto fabric;
ferr = PX_NO_PANIC;
}
}