px_tools_4u.c revision e51949e6deb4cb79dcb0772d225868626ae52517
/*
* 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 2006 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/machsystm.h>
#include <sys/ddi_implfuncs.h>
#include <px_csr.h>
#include <px_regs.h>
#include <px_obj.h>
#include <sys/pci_tools.h>
#include <px_tools_var.h>
#include <px_asm_4u.h>
#include <px_lib4u.h>
#include <px_tools_ext.h>
/*
* Delay needed to have a safe environment envelop any error which could
* surface. The larger the number of bridges and switches, the larger the
* number needed here.
*
* The way it works is as follows:
*
* An access is done which causes an error. Fire errors are handled with
* ontrap protection and usually come in first. Fabric errors can come in
* later.
*
* px_phys_peek_4u() disables interrupts. Interrupts are reenabled at the end
* of that function if no errors have been caught by the trap handler, or by
* peek_fault() which executes when a fire error occurs.
*
* Fabric error messages get put on an event queue but are not processed until
* interrupts are reenabled.
*
* The delay gives time for the fabric errors to be processed by FMA before
* changing the fm error flag back to DDI_FM_ERR_UNEXPECTED. If this isn't
* done, then the fabric error which should be safe can panic the system.
*
* Note: this is a workaround until a better solution is found. While this
* number is high, given enough bridges and switches in the device path, this
* workaround can break. Also, other PIL 15 interrupts besides the ones we are
* enveloping could delay processing of the interrupt we are trying to protect.
*/
int pxtool_delay_ticks = 1;
/* Number of inos per root complex. */
/* Mechanism for getting offsets of smaller datatypes aligned in 64 bit long */
typedef union {
/*
* Safe C wrapper around assy language routine px_phys_peek_4u
*
* Type is TRUE for big endian, FALSE for little endian.
* Size is 1, 2, 4 or 8 bytes.
* paddr is the physical address in IO space to access read.
* value_p is where the value is returned.
*/
static int
{
int err = DDI_SUCCESS;
/*
* Set up trap handling to make the access safe.
*
* on_trap works like setjmp.
* Set it up to not panic on data access error,
* but to call peek_fault instead.
* Call px_phys_peek_4u after trap handling is setup.
* When on_trap returns FALSE, it has been setup.
* When it returns TRUE, an it has caught an error.
*/
} else
err = DDI_FAILURE;
no_trap();
/*
* Workaround: delay taking down safe access env.
* For more info, see comments where pxtool_delay_ticks is declared.
*/
if (pxtool_delay_ticks > 0)
if (err != DDI_FAILURE) {
switch (size) {
case 8:
break;
case 4:
break;
case 2:
break;
case 1:
break;
default:
err = DDI_FAILURE;
}
}
return (err);
}
/*
* Safe C wrapper around assy language routine px_phys_poke_4u
*
* Type is TRUE for big endian, FALSE for little endian.
* Size is 1,2,4 or 8 bytes.
* paddr is the physical address in IO space to access read.
* value contains the value to be written.
*/
static int
{
int err = DDI_SUCCESS;
switch (size) {
case 8:
break;
case 4:
break;
case 2:
break;
case 1:
break;
default:
return (DDI_FAILURE);
}
/*
* on_trap works like setjmp.
* Set it up to not panic on data access error,
* but to call poke_fault instead.
* Call px_phys_poke_4u after trap handling is setup.
* When on_trap returns FALSE, it has been setup.
* When it returns TRUE, an it has caught an error.
*/
} else
err = DDI_FAILURE;
err = DDI_FAILURE;
/* Take down protected environment. */
no_trap();
/*
* Workaround: delay taking down safe access env.
* For more info, see comments where pxtool_delay_ticks is declared.
*/
if (pxtool_delay_ticks > 0)
return (err);
}
/*
* Wrapper around pxtool_safe_phys_peek/poke.
*
* Validates arguments and calls pxtool_safe_phys_peek/poke appropriately.
*
* Dip is of the nexus,
* phys_addr is the address to write in physical space.
* pcitool_status returns more detailed status in addition to a more generic
* errno-style function return value.
* other args are self-explanatory.
*
* This function assumes that offset, bdf, and acc_attr are current in
* prg_p. It also assumes that prg_p->phys_addr is the final phys addr,
* including offset.
* This function modifies prg_p status and data.
*/
/*ARGSUSED*/
static int
{
/* Alignment checking. Assumes base address is 8-byte aligned. */
} else if (is_write) { /* Made it through checks. Do the access. */
*data_p) != DDI_SUCCESS) {
"%d byte %s pxtool_safe_phys_poke at addr "
}
} else { /* Read */
data_p) != DDI_SUCCESS) {
"%d byte %s pxtool_safe_phys_peek at addr "
}
}
return (rval);
}
int
{
}
int
{
}
int
{
/*
* Guard against checking a root nexus which is empty.
* On some systems this will result in a Fatal Reset.
*/
return (ENXIO);
}
return (SUCCESS);
}
/*
* Perform register accesses on the nexus device itself.
*/
int
{
if (cmd == PCITOOL_NEXUS_SET_REG)
write_flag = B_TRUE;
/* Read data from userland. */
DDI_SUCCESS) {
return (EFAULT);
}
/* Read reg property which contains starting addr and size of banks. */
if (((reglen * sizeof (int)) %
sizeof (px_nexus_regspec_t)) != 0) {
goto done;
}
}
/* Bounds check the bank number. */
goto done;
}
goto done;
}
/* Access device. prg.status is modified. */
done:
mode) != DDI_SUCCESS) {
return (EFAULT);
}
return (rval);
}