pcifm.c revision f41150baf74bdaf964ddfe42d865d3c2380b3623
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/ddifm_impl.h>
#include <sys/pci_impl.h>
#define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\
((x) == PCI_PCIX_VER_2))
/*
* Expected PCI Express error mask values
*
* !!NOTE!! All PCI Express functionality including PCIe initialization, PCIe
* error handling has been moved to the common pcie misc module. All functions
* and variables dealting with PCIe in this file have been deprecated and will
* be eventually removed. All Legacy PCI and PCI-X related code should remain
* as is.
*/
pci_fm_err_t pci_err_tbl[] = {
};
pci_fm_err_t pci_bdg_err_tbl[] = {
#if defined(__sparc)
#endif
};
static pci_fm_err_t pciex_ce_err_tbl[] = {
};
static pci_fm_err_t pciex_ue_err_tbl[] = {
};
static pci_fm_err_t pcie_sue_err_tbl[] = {
#if defined(__sparc)
#endif
};
static pci_fm_err_t pcix_err_tbl[] = {
};
static pci_fm_err_t pcix_sec_err_tbl[] = {
};
static pci_fm_err_t pciex_nadv_err_tbl[] = {
};
static int
{
return (DDI_FM_OK);
if (fme_flag == DDI_FM_ERR_UNEXPECTED) {
char buf[FM_MAX_CLASS];
}
}
return (de.fme_status);
}
static void
{
else
return;
}
static void
{
int i;
else
return;
else
return;
/*
* PCI Express to PCI-X bridges only implement the
* secondary side of the PCI-X ECC registers, bit one is
* read-only so we make sure we do not write to it.
*/
} else {
for (i = 0; i < 2; i++) {
PCI_PCIX_BDG_ECC_STATUS), i);
}
}
}
} else {
(pcix_cap_ptr + PCI_PCIX_COMMAND));
(pcix_cap_ptr + PCI_PCIX_STATUS));
else
return;
}
}
}
static void
{
else
return;
(pcie_cap_ptr + PCIE_DEVCTL));
(pcie_cap_ptr + PCIE_DEVCAP));
PCIX_DEV))
(pcie_cap_ptr + PCIE_ROOTSTS));
(pcie_cap_ptr + PCIE_ROOTCTL));
}
return;
int i;
for (i = 0; i < 3; i++) {
(4 * (i + 1)));
}
}
/*
* If pci express to pci bridge then grab the bridge
* error registers.
*/
int i;
for (i = 0; i < 3; i++) {
pcie_bdg_regs->pcie_sue_hdr[i] =
(4 * (i + 1)));
}
}
}
/*
* If PCI Express root complex then grab the root complex
* error registers.
*/
(pcie_ecap_ptr + PCIE_AER_RE_CMD));
(pcie_ecap_ptr + PCIE_AER_RE_STS));
}
}
/*ARGSUSED*/
static void
{
/*
* Start by reading all the error registers that are available for
*/
return;
return;
/*
* If pci-pci bridge grab PCI bridge specific error registers.
*/
}
/*
* If pci express device grab pci express error registers and
* check for advanced error reporting features and grab them if
* available.
*/
}
static void
{
int i;
/*
* PCI Express to PCI-X bridges only implement the
* secondary side of the PCI-X ECC registers, bit one is
* read-only so we make sure we do not write to it.
*/
if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
}
} else {
for (i = 0; i < 2; i++) {
if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
i);
}
0x0;
}
}
}
} else {
if (pcix_ecc_regs->pcix_ecc_vflags &
}
}
}
static void
{
return;
}
/*
* If PCI Express root complex then clear the root complex
* error registers.
*/
}
}
static void
{
/*
* Finally clear the error bits
*/
}
}
/*
* pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport
* generation.
*/
/* ARGSUSED */
static void
{
int i;
"pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
else
return;
KM_SLEEP);
for (i = 0; i < 2; i++) {
kmem_zalloc(sizeof (pcix_ecc_regs_t),
KM_SLEEP);
}
}
} else {
KM_SLEEP);
sizeof (pcix_ecc_regs_t), KM_SLEEP);
}
}
}
static void
{
/*
* The following sparc specific code should be removed once the pci_cap
* interfaces create the necessary properties for us.
*/
#if defined(__sparc)
DDI_FM_OK) {
0xff) {
if (cap_id == PCI_CAP_ID_PCIX) {
"pcix-capid-pointer", cap_ptr);
}
if (cap_id == PCI_CAP_ID_PCI_E) {
if (status & PCIE_PCIECAP_SLOT_IMPL) {
/* offset 14h is Slot Cap Register */
cap_ptr + PCIE_SLOTCAP);
"pcie-slotcap-reg", slot_cap);
}
cap_ptr + PCIE_PCIECAP));
"pcie-capid-pointer", cap_ptr);
}
break;
}
}
#endif
"pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
if (pcie_cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
KM_SLEEP);
}
return;
/*
* Don't currently need to check for version here because we are
* compliant with PCIE 1.0a which is version 0 and is guaranteed
* software compatibility with future versions. We will need to
* revisions [sec 7.8.2].
*/
int i;
for (i = 0; i < 2; i++)
kmem_zalloc(sizeof (pcix_ecc_regs_t),
KM_SLEEP);
}
if (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) {
sizeof (pcie_rc_error_regs_t), KM_SLEEP);
}
/*
* The following sparc specific code should be removed once the pci_cap
* interfaces create the necessary properties for us.
*/
#if defined(__sparc)
while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) &&
(hdr_cap_id != PCIE_EXT_CAP_ID_AER)) {
}
if (hdr_cap_id == PCIE_EXT_CAP_ID_AER)
if (aer_ptr != PCI_CAP_NEXT_PTR_NULL)
"pcie-aer-pointer", aer_ptr);
#endif
/*
* Find and store if this device is capable of pci express
* advanced errors, if not report an error against the device.
*/
"pcie-aer-pointer", PCI_CAP_NEXT_PTR_NULL);
if (pcie_ecap_ptr != PCI_CAP_NEXT_PTR_NULL) {
sizeof (pcie_adv_error_regs_t), KM_SLEEP);
}
return;
}
if (pcie_adv_regs == NULL)
return;
/*
* Initialize structures for advanced PCI Express devices.
*/
/*
* Advanced error registers exist for PCI Express to PCI(X) Bridges and
* may also exist for PCI(X) to PCI Express Bridges, the latter is not
* 1.0 and will be left out of the current gathering of these registers.
*/
if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
sizeof (pcie_adv_bdg_error_regs_t), KM_SLEEP);
}
sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP);
}
/*
* pci_ereport_setup: Detect PCI device type and initialize structures to be
* used to generate ereports based on detected generic device errors.
*/
void
{
/*
* If device is not ereport capbable then report an error against the
* driver for using this interface,
*/
return;
}
/*
* ASSERT fmhdl exists and fh_bus_specific is NULL.
*/
goto error;
goto error;
/*
* Get header type and record if device is a bridge.
*/
goto error;
/*
* Check to see if PCI device is a bridge, if so allocate pci bridge
* error register structure.
*/
sizeof (pci_bdg_error_regs_t), KM_SLEEP);
}
}
if (!(pci_status & PCI_STAT_CAP)) {
goto done;
}
/*
* Initialize structures for PCI Express and PCI-X devices.
* Order matters below and pcie_ereport_setup should preceed
* pcix_ereport_setup.
*/
}
done:
/*
* Before returning set fh_bus_specific to completed pci_erpt_t
* structure
*/
return;
if (erpt_p->pe_pci_regs)
}
static void
{
if (PCIX_ECC_VER_CHECK(pcix_ver)) {
int i;
for (i = 0; i < 2; i++)
sizeof (pcix_ecc_regs_t));
}
} else {
if (PCIX_ECC_VER_CHECK(pcix_ver)) {
sizeof (pcix_ecc_regs_t));
}
}
}
static void
{
sizeof (pcie_adv_bdg_error_regs_t));
sizeof (pcie_adv_rc_error_regs_t));
}
sizeof (pcie_rc_error_regs_t));
if (PCIX_ECC_VER_CHECK(pcix_ver)) {
int i;
for (i = 0; i < 2; i++)
sizeof (pcix_ecc_regs_t));
}
sizeof (pcix_bdg_error_regs_t));
}
}
}
void
{
}
return;
sizeof (pci_bdg_error_regs_t));
/*
* The following sparc specific code should be removed once the pci_cap
* interfaces create the necessary properties for us.
*/
#if defined(__sparc)
#endif
}
static void
{
switch (errtype) {
case PCIEX_TYPE_CE:
break;
case PCIEX_TYPE_UE:
1 : NULL,
#ifdef DEBUG
pcie_adv_regs->pcie_ue_hdr[0],
#endif
NULL);
break;
case PCIEX_TYPE_GEN:
break;
case PCIEX_TYPE_RC_UE_MSG:
case PCIEX_TYPE_RC_CE_MSG:
(errtype == PCIEX_TYPE_RC_UE_MSG) ?
(errtype == PCIEX_TYPE_RC_UE_MSG) ?
pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) :
break;
case PCIEX_TYPE_RC_MULT_MSG:
break;
default:
break;
}
}
/*ARGSUSED*/
static void
{
int upstream = 0;
return;
upstream = 1;
case PCIE_TLP_TYPE_MEM:
case PCIE_TLP_TYPE_MEMLK:
} else {
}
if (upstream) {
}
break;
case PCIE_TLP_TYPE_IO:
{
}
break;
}
case PCIE_TLP_TYPE_CFG0:
case PCIE_TLP_TYPE_CFG1:
{
break;
}
case PCIE_TLP_TYPE_MSG:
{
break;
}
case PCIE_TLP_TYPE_CPL:
case PCIE_TLP_TYPE_CPLLK:
{
if (upstream) {
} else {
}
break;
}
case PCIE_TLP_TYPE_MSI:
default:
break;
}
}
/*ARGSUSED*/
static void
int type)
{
int cmd;
int dual_addr = 0;
return;
switch (cmd) {
case PCI_PCIX_CMD_IORD:
case PCI_PCIX_CMD_IOWR:
if (addr) {
}
break;
case PCI_PCIX_CMD_MEMRD_DW:
case PCI_PCIX_CMD_MEMWR:
case PCI_PCIX_CMD_MEMRD_BL:
case PCI_PCIX_CMD_MEMWR_BL:
case PCI_PCIX_CMD_MEMRDBL:
case PCI_PCIX_CMD_MEMWRBL:
if (addr) {
}
break;
case PCI_PCIX_CMD_CFRD:
case PCI_PCIX_CMD_CFWR:
/*
* for type 1 config transaction we can find bdf from address
*/
}
break;
case PCI_PCIX_CMD_SPL:
if (type == ACC_HANDLE) {
}
break;
case PCI_PCIX_CMD_DADR:
if (dual_addr)
break;
++dual_addr;
goto cmd_switch;
default:
break;
}
}
/*ARGSUSED*/
static int
{
switch (cmd) {
case PCI_PCIX_CMD_INTR:
case PCI_PCIX_CMD_SPEC:
return (DDI_FM_FATAL);
case PCI_PCIX_CMD_IORD:
case PCI_PCIX_CMD_IOWR:
return (DDI_FM_UNKNOWN);
case PCI_PCIX_CMD_DEVID:
return (DDI_FM_FATAL);
case PCI_PCIX_CMD_MEMRD_DW:
case PCI_PCIX_CMD_MEMWR:
case PCI_PCIX_CMD_MEMRD_BL:
case PCI_PCIX_CMD_MEMWR_BL:
return (DDI_FM_UNKNOWN);
case PCI_PCIX_CMD_CFRD:
case PCI_PCIX_CMD_CFWR:
/*
* for type 1 config transaction we can find bdf from address
*/
}
return (DDI_FM_UNKNOWN);
case PCI_PCIX_CMD_SPL:
case PCI_PCIX_CMD_DADR:
return (DDI_FM_UNKNOWN);
case PCI_PCIX_CMD_MEMRDBL:
case PCI_PCIX_CMD_MEMWRBL:
return (DDI_FM_UNKNOWN);
default:
return (DDI_FM_FATAL);
}
}
/*ARGSUSED*/
static int
{
int fatal = 0;
int nonfatal = 0;
int unknown = 0;
int ok = 0;
char buf[FM_MAX_CLASS];
int i;
goto done;
unknown++;
}
if (pci_bdg_regs->pci_bdg_sec_stat &
pci_bdg_err_tbl[i].reg_bit) {
pci_bdg_err_tbl[i].err_class);
}
}
#if !defined(__sparc)
/*
* For x86, many drivers and even user-level code currently get
* away with accessing bad addresses, getting a UR and getting
* -1 returned. Unfortunately, we have no control over this, so
* we will have to treat all URs as nonfatal. Moreover, if the
* leaf driver is non-hardened, then we don't actually see the
* UR directly. All we see is a secondary bus master abort at
* the root complex - so it's this condition that we actually
* need to treat as nonfatal (providing no other unrelated nfe
* conditions have also been seen by the root complex).
*/
!(pcie_regs->pcie_err_status &
nonfatal++;
if ((pcie_adv_regs->pcie_adv_vflags &
"%s.%s-%s", PCI_ERROR_SUBCLASS,
}
}
}
#endif
}
done:
/*
* Need to check for poke and cautious put. We already know peek
* and cautious get errors occurred (as we got a trap) and we know
* they are nonfatal.
*/
/*
* for cautious puts we treat all errors as nonfatal. Actually
* we set nonfatal for cautious gets as well - doesn't do any
* harm
*/
nonfatal++;
}
/*
* special case for pokes - we only consider master abort
* and target abort as nonfatal. Sserr with no master abort is
* instance, so return unknown and parent will determine if
* nonfatal (if another child returned nonfatal - ie master
* or target abort) or fatal otherwise
*/
nonfatal++;
unknown++;
}
/*
* now check children below the bridge
*/
}
static int
void *pe_regs)
{
int bridge;
int i;
int ecc_phase;
int ecc_corr;
int sec_ue;
int sec_ce;
int fatal = 0;
int nonfatal = 0;
int unknown = 0;
int ok = 0;
char buf[FM_MAX_CLASS];
bridge = 1;
} else {
bridge = 0;
}
PCI_PCIX_ECC_PHASE) >> 0x4;
switch (ecc_phase) {
case PCI_PCIX_ECC_PHASE_NOERR:
break;
case PCI_PCIX_ECC_PHASE_FADDR:
case PCI_PCIX_ECC_PHASE_SADDR:
"%s.%s%s", PCIX_ERROR_SUBCLASS,
i ? PCIX_SEC_ERROR_SUBCLASS : "",
break;
case PCI_PCIX_ECC_PHASE_ATTR:
"%s.%s%s", PCIX_ERROR_SUBCLASS,
i ? PCIX_SEC_ERROR_SUBCLASS : "",
break;
if (ecc_corr)
else {
int type;
if (i) {
if (pci_regs->pci_bdg_regs->
type = ACC_HANDLE;
else
type = DMA_HANDLE;
} else {
if (pci_regs->pci_err_status &
type = DMA_HANDLE;
else
type = ACC_HANDLE;
}
}
"%s.%s%s", PCIX_ERROR_SUBCLASS,
i ? PCIX_SEC_ERROR_SUBCLASS : "",
break;
}
if (ecc_phase)
if (bridge)
DATA_TYPE_UINT8, 0,
else
DATA_TYPE_UINT8, 0,
"%s.%s%s", PCIX_ERROR_SUBCLASS,
i ? PCIX_SEC_ERROR_SUBCLASS : "",
if (bridge)
DATA_TYPE_UINT8, 0,
else
DATA_TYPE_UINT8, 0,
}
}
}
}
static int
void *pe_regs)
{
int fatal = 0;
int nonfatal = 0;
int unknown = 0;
int ok = 0;
char buf[FM_MAX_CLASS];
int i;
if ((pcix_bdg_regs->pcix_bdg_stat &
pcix_err_tbl[i].reg_bit)) {
pcix_err_tbl[i].err_class);
}
}
}
if ((pcix_bdg_regs->pcix_bdg_sec_stat &
pcix_sec_err_tbl[i].reg_bit)) {
}
}
}
int ret;
(void *)pcix_bdg_regs);
}
}
static int
{
int fatal = 0;
int nonfatal = 0;
int unknown = 0;
int ok = 0;
char buf[FM_MAX_CLASS];
int i;
continue;
NULL);
}
}
(void *)pcix_regs);
}
}
static int
void *pe_regs)
{
int fatal = 0;
int nonfatal = 0;
int unknown = 0;
char buf[FM_MAX_CLASS];
/*
* recieved by root complex
*/
fatal++;
if (fe && first_ue_fatal) {
}
if (nfe && !first_ue_fatal) {
}
if (ce) {
}
if (mult_ce) {
}
if (mult_ue) {
}
}
}
static int
{
int fatal = 0;
int nonfatal = 0;
int unknown = 0;
int ok = 0;
int type;
char buf[FM_MAX_CLASS];
int i;
(void *)pcie_regs->pcix_bdg_regs);
}
goto done;
#if !defined(__sparc)
/*
* On x86 ignore UR on non-RBER leaf devices, pciex-pci
* bridges and switches.
*/
goto done;
#endif
if (!(pcie_regs->pcie_err_status &
continue;
}
goto done;
}
/*
* Log PCI Express uncorrectable errors
*/
if (!(pcie_adv_regs->pcie_ue_status &
pciex_ue_err_tbl[i].reg_bit))
continue;
"%s.%s", PCIEX_ERROR_SUBCLASS,
/*
* First check for advisary nonfatal conditions
* - hardware endpoint successfully retrying a cto
* - hardware endpoint receiving poisoned tlp and
* dealing with it itself (but not if root complex)
* If the device has declared these as correctable
* errors then treat them as such.
*/
!(pcie_regs->pcie_err_status &
continue;
}
#if !defined(__sparc)
/*
* On x86 for leaf devices and pciex-pci bridges,
* ignore UR on non-RBER devices or on RBER devices when
* advisory nonfatal.
*/
if (!(pcie_regs->pcie_dev_cap &
continue;
if (!(pcie_regs->pcie_err_status &
continue;
}
#endif
pcie_adv_regs->pcie_adv_bdf = 0;
/*
* Now try and look up handle if
* - error bit is among PCIE_AER_UCE_LOG_BITS, and
* - no other PCIE_AER_UCE_LOG_BITS are set, and
* - error bit is not masked, and
* - flag is DDI_FM_UNKNOWN
*/
if ((pcie_adv_regs->pcie_ue_status &
pciex_ue_err_tbl[i].reg_bit &&
!(pciex_ue_err_tbl[i].reg_bit &
}
}
/*
* Log PCI Express correctable errors
*/
if (!(pcie_adv_regs->pcie_ce_status &
pciex_ce_err_tbl[i].reg_bit))
continue;
"%s.%s", PCIEX_ERROR_SUBCLASS,
}
}
goto done;
(void *)pcie_adv_regs);
}
goto done;
if ((pcie_bdg_regs->pcie_sue_status &
pcie_sue_err_tbl[i].reg_bit)) {
if ((pcie_bdg_regs->pcie_sue_status &
pcie_sue_err_tbl[i].reg_bit ||
#ifdef DEBUG
#endif
NULL);
} else {
pcie_adv_regs->pcie_adv_bdf = 0;
switch (pcie_sue_err_tbl[i].reg_bit) {
case PCIE_AER_SUCE_RCVD_TA:
case PCIE_AER_SUCE_RCVD_MA:
case PCIE_AER_SUCE_USC_ERR:
type = ACC_HANDLE;
break;
case PCIE_AER_SUCE_TA_ON_SC:
case PCIE_AER_SUCE_MA_ON_SC:
type = DMA_HANDLE;
break;
type = ACC_HANDLE;
else
type = DMA_HANDLE;
break;
}
1 : NULL,
#ifdef DEBUG
#endif
NULL);
}
}
}
done:
}
static void
{
int fatal = 0;
int nonfatal = 0;
int unknown = 0;
int ok = 0;
char buf[FM_MAX_CLASS];
int i;
/*
* Log generic PCI errors.
*/
pci_err_tbl[i].reg_bit) ||
continue;
/*
* Generate an ereport for this error bit.
*/
/*
* The meaning of SERR is different for PCIEX (just
* implies a message has been sent) so we don't want to
* treat that one as fatal.
*/
unknown++;
} else {
}
}
} else {
}
}
}
}
int ret = DDI_FM_UNKNOWN;
(void *)&pci_fme_bsp->pci_bs_addr);
}
/*
* If we didn't find the handle using an addr, try using bdf.
* Note we don't do this where the bdf is for a
* fabricated the bdf.
*/
if (ret == DDI_FM_UNKNOWN &&
}
}
}
void
{
struct i_ddi_fmhdl *fmhdl;
/*
* On PCI Express systems, all error handling and ereport are done via
* the PCIe misc module. This function is a no-op for PCIe Systems. In
* order to tell if a system is a PCI or PCIe system, check that the
* bus_private_data exists. If it exists, this is a PCIe system.
*/
*xx_status = 0x0;
return;
}
return;
}
/*
* copy in the ddi_fm_error_t structure in case it's VER0
*/
else
/*
* if this is the first pci device we've found convert
* fme_bus_specific to DDI_FME_BUS_TYPE_PCI
*/
if (de.fme_bus_specific) {
/*
* the cpu passed us an addr - this can be used to look
* up an access handle
*/
}
}
return;
}
/*
* private version of walk_devs() that can be used during panic. No
* sleeping or locking required.
*/
static int
{
while (dip) {
case DDI_WALK_TERMINATE:
return (DDI_WALK_TERMINATE);
case DDI_WALK_CONTINUE:
arg) == DDI_WALK_TERMINATE)
return (DDI_WALK_TERMINATE);
break;
case DDI_WALK_PRUNECHILD:
break;
}
}
return (DDI_WALK_CONTINUE);
}
/*
* need special version of ddi_fm_ereport_post() as the leaf driver may
* not be hardened.
*/
static void
{
char *name;
char device_path[MAXPATHLEN];
char ddi_error_class[FM_MAX_CLASS];
if (panicstr) {
return;
} else {
}
device_path, NULL);
if (panicstr) {
} else {
}
}
static int
{
int reglen;
int rn;
int totreg;
/*
* for config space, we need to check if the given address
* is a valid config space address for this device - based
* on pci_phys_hi of the config space entry in reg property.
*/
return (DDI_WALK_CONTINUE);
if (tgt_err->tgt_pci_space ==
PCI_REG_DEV_M | PCI_REG_FUNC_M)) ==
PCI_REG_DEV_M | PCI_REG_FUNC_M))) {
return (DDI_WALK_TERMINATE);
}
}
} else {
/*
* for non config space, need to check reg to look
* for any non-relocable mapping, otherwise check
* assigned-addresses.
*/
return (DDI_WALK_CONTINUE);
tgt_err->tgt_pci_space ==
(tgt_err->tgt_pci_addr >=
(tgt_err->tgt_pci_addr <
return (DDI_WALK_TERMINATE);
}
}
return (DDI_WALK_CONTINUE);
tgt_err->tgt_pci_space ==
(tgt_err->tgt_pci_addr >=
(tgt_err->tgt_pci_addr <
return (DDI_WALK_TERMINATE);
}
}
}
return (DDI_WALK_CONTINUE);
}
/*
* impl_fix_ranges - fixes the config space entry of the "ranges"
* property on psycho+ platforms. (if changing this function please make sure
* to change the pci_fix_ranges function in pcipsy.c)
*/
/*ARGSUSED*/
static void
{
#if defined(__sparc)
int i;
for (i = 0; i < nrange; i++, pci_ranges++)
pci_ranges->parent_low |=
}
#endif
}
static int
{
int pci_ranges_length;
int nrange;
int i, size;
return (DDI_WALK_CONTINUE);
/*
* Get the ranges property. Note we only look at the top level pci
* node (hostbridge) which has a ranges property of type pci_ranges_t
* not at pci-pci bridges.
*/
/*
* no ranges property - no translation needed
*/
if (panicstr)
pci_check_regs, (void *)tgt_err);
else {
int circ = 0;
(void *)tgt_err);
}
return (DDI_WALK_TERMINATE);
return (DDI_WALK_PRUNECHILD);
}
rangep = pci_ranges;
/* Need to fix the pci ranges property for psycho based systems */
/* Not in range */
continue;
}
/* Config space address - check bus range */
DDI_PROP_DONTPASS, "bus-range",
continue;
}
/*
* Bus number not appropriate for this
* pci nexus.
*/
continue;
}
}
/* We have a match if we get here - compute pci address */
if (panicstr)
pci_check_regs, (void *)tgt_err);
else {
int circ = 0;
(void *)tgt_err);
}
return (DDI_WALK_TERMINATE);
}
}
return (DDI_WALK_PRUNECHILD);
}
/*
* Function used to drain pci_target_queue, either during panic or after softint
* is generated, to generate target device ereports based on captured physical
* addresses
*/
/*ARGSUSED*/
static void
{
char buf[FM_MAX_CLASS];
/*
* The following assumes that all pci_pci bridge devices
* are configured as transparant. Find the top-level pci
* nexus which has tgt_err_addr in one of its ranges, converting this
* to a pci address in the process. Then starting at this node do
* another tree walk to find a device with the pci address we've
* found within range of one of it's assigned-addresses properties.
*/
if (panicstr)
(void *)tgt_err);
else
(void *)tgt_err);
return;
}
void
{
sizeof (pci_target_err_t), ERRORQ_ASYNC);
}
void
pci_targetq_init(void)
{
/*
* PCI target errorq, to schedule async handling of generation of
* target device ereports based on captured physical address.
* The errorq is created here but destroyed when _fini is called
* for the pci module.
*/
if (pci_target_queue == NULL) {
if (pci_target_queue == NULL)
panic("failed to create required system error queue");
}
}