px_tools.c revision dabea0db6f27d1bf410afbc09b7dcec947a03164
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "px_obj.h"
#include <sys/pci_tools.h>
#include "px_tools_ext.h"
#include "px_tools_var.h"
/*
* PCI Space definitions.
*/
/*
* Config space range for a device. IEEE 1275 spec defines for PCI.
* Space for PCI-express is multiplied by PX_PCI_BDF_OFFSET_DELTA
*/
#define DEV_CFG_SPACE_SIZE \
/*
* Offsets of BARS in config space. First entry of 0 means config space.
* Entries here correlate to pcitool_bars_t enumerated type.
*/
0x0,
};
/*
* Validate the cpu_id passed in.
* A value of 1 will be returned for success and zero for failure.
*/
static int
{
extern const int _ncpu;
}
static int
{
return (EFAULT);
else
return (SUCCESS);
}
/*
* Get interrupt information for a given ino.
* Returns info only for inos mapped to devices.
*
* Returned info is valid only when iget.num_devs is returned > 0.
* If ino is not enabled or is not mapped to a device,
* iget.num_devs will be returned as = 0.
*/
/*ARGSUSED*/
static int
{
/* Array part isn't used here, but oh well... */
int copyout_rval;
/* Read in just the header part, no array section. */
return (EFAULT);
/* Validate argument. */
goto done_get_intr;
}
/* Caller wants device information returned. */
if (num_devs_ret > 0) {
/*
* Allocate room.
* Note if num_devs == 0 iget remains pointing to
* partial_iget.
*/
/* Read in whole structure to verify there's room. */
SUCCESS) {
/* Be consistent and just return EFAULT here. */
return (EFAULT);
}
}
/* Convert leaf-wide intr to system-wide intr */
DDI_FAILURE) {
goto done_get_intr;
}
/* Operate only on inos which are already enabled. */
DDI_FAILURE) {
goto done_get_intr;
}
/*
* Consider all valid inos: those mapped to the root complex itself
* as well as those mapped to devices.
*/
if (intr_valid_state == INTR_VALID) {
/*
* The following looks up the px_ib_ino_info and returns
* info of devices mapped to this ino.
*/
DDI_FAILURE) {
goto done_get_intr;
}
}
if (iget_kmem_alloc_size > 0)
if (copyout_rval != DDI_SUCCESS)
return (rval);
}
/*
* Associate a new CPU with a given ino.
*
* Operate only on inos which are already mapped to devices.
*/
static int
{
return (EFAULT);
/* Validate input argument. */
goto done_set_intr;
/* Validate that ino given belongs to a device. */
goto done_set_intr;
/*
* Get lock, validate cpu and write new mapreg value.
* Return original cpu value to caller via iset.cpu.
*/
goto done_set_intr;
goto done_set_intr;
} else { /* Invalid cpu. Restore original register image. */
"Invalid cpuid: writing orig mapreg value\n");
}
return (rval);
}
/* Main function for handling interrupt CPU binding requests and queries. */
int
{
switch (cmd) {
/* Return the number of interrupts supported by a PCI bus. */
case PCITOOL_DEVICE_NUM_INTR:
break;
/* Get interrupt information for a given ino. */
case PCITOOL_DEVICE_GET_INTR:
break;
/* Associate a new CPU with a given ino. */
case PCITOOL_DEVICE_SET_INTR:
break;
default:
}
return (rval);
}
static int
{
/* Validate address arguments of bus / dev / func */
}
return (rval);
}
/*
* px_p defines which leaf, space defines which space in that leaf, offset
* defines the offset within the specified space.
*
* This returns the physical address of the corresponding location.
*/
static uintptr_t
{
int rval;
uint32_t base_offset = 0;
/*
* Assume that requested entity is small enough to be on the same page.
* (Same starting and ending value "offset" passed to px_search_ranges.)
* PCItool checks alignment so that this will be true for single
* accesses.
*
* Base_offset is the offset from the specified address, where the
* current range begins. This is nonzero when a PCI space is split and
* the address is inside the second or subsequent range.
*
* NOTE: offset is a uint64_t but px_search_ranges takes a uint32_t.
* px_search_ranges should also take a uint64_t for base_offset.
* RFE is to have px_search_ranges handle a uint64_t offset.
*/
(uint32_t *)&base_offset);
if (rval != DDI_SUCCESS)
return (NULL);
else {
rp->parent_low;
return (base_offset + range_base);
}
}
static int
{
int rval;
*bar_p = 0;
/*
* Translate BAR number into offset of the BAR in
* the device's config space.
*/
/*
* Note: sun4u acc function uses phys_addr which includes offset.
* sun4v acc function doesn't use phys_addr but uses cfg_prg.offset.
*/
/*
* Get Bus Address Register (BAR) from config space.
* cfg_prg.offset is the offset into config space of the
* BAR desired. prg_p->status is modified on error.
*/
return (rval);
}
/*
* BAR has bits saying this space is IO space, unless
* this is the ROM address register.
*/
*space_p = PCI_IO_SPACE;
*bar_p &= PCI_BASE_IO_ADDR_M;
/*
* BAR has bits saying this space is 64 bit memory
* space, unless this is the ROM address register.
*
* The 64 bit address stored in two BAR cells is not
* necessarily aligned on an 8-byte boundary.
* Need to keep the first 4 bytes read,
* and do a separate read of the high 4 bytes.
*/
} else if ((PCI_BASE_TYPE_ALL & *bar_p) &&
/* Don't try to read the next 4 bytes past the end of BARs. */
return (EIO);
}
/* Access device. prg_p->status is modified on error. */
return (rval);
}
/*
* Honor the 64 bit BAR as such, only when the upper 32 bits
* store a non-zero value.
*/
if (*bar_p) {
} else
/*
* ROM enabled. Filter ROM enable bit from the BAR.
* Treat as Mem32 henceforth.
*/
if (!(*bar_p & PCI_BASE_ROM_ENABLE))
*bar_p ^= PCI_BASE_ROM_ENABLE;
else { /* ROM disabled. */
return (EIO);
}
}
/* Accept a bar of 0 only for IO space. */
return (EINVAL);
}
return (SUCCESS);
}
/* Perform register accesses on PCI leaf devices. */
int
{
int rval = 0;
if (cmd == PCITOOL_DEVICE_SET_REG)
write_flag = B_TRUE;
mode) != DDI_SUCCESS) {
return (EFAULT);
}
goto done_reg;
}
goto done_reg;
/* Enforce offset limits. */
goto done_reg;
}
/*
* For sun4v, config space base won't be known.
* pxtool_get_phys_addr will return zero.
* Note that for sun4v, phys_addr isn't
* used for making config space accesses.
*
* For sun4u, assume that phys_addr will come back valid.
*/
/* Accessed entity is assumed small enough to be on one page. */
/*
* Access device. pr.status is modified.
* BDF is assumed valid at this point.
*/
goto done_reg;
}
/* IO/ MEM/ MEM64 space. */
goto done_reg;
switch (space) {
case PCI_MEM32_SPACE:
/* Can't write to ROM */
goto done_reg;
}
break;
case PCI_IO_SPACE:
break;
case PCI_MEM64_SPACE:
break;
default:
goto done_reg;
}
/*
*
* Use offset provided by caller to index into desired space.
* Note that prg.status is modified on error.
*/
mode) != DDI_SUCCESS) {
}
return (rval);
}
int
{
DDI_NT_REGACC, 0) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
DDI_NT_INTRCTL, 0) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
{
}