pcmu_util.c revision 07d06da50d310a325b457d6330165aebab1e0064
/*
* 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.
*/
/*
* CMU-CH nexus utility routines:
* property and config routines for attach()
* reg/intr/range/assigned-address property routines for bus_map()
* init_child()
* fault handling
* debug functions
*/
#include <sys/sysmacros.h>
#include <sys/ddi_impldefs.h>
/*
* get_pcmu_properties
*
* This function is called from the attach routine to get the key
* properties of the pci nodes.
*
* used by: pcmu_attach()
*
* return value: DDI_FAILURE on failure
*/
int
{
int i;
/*
* Get the device's port id.
*/
return (DDI_FAILURE);
}
/*
* Get the bus-ranges property.
*/
i = sizeof (pcmu_p->pcmu_bus_range);
return (DDI_FAILURE);
}
"get_pcmu_properties: bus-range (%x,%x)\n",
/*
* Get the ranges property.
*/
DDI_SUCCESS) {
return (DDI_FAILURE);
}
/*
* Determine the number upa slot interrupts.
*/
return (DDI_SUCCESS);
}
/*
* free_pcmu_properties:
*
* This routine frees the memory used to cache the
* "ranges" properties of the pci bus device node.
*
* used by: pcmu_detach()
*
* return value: none
*/
void
{
}
/*
* pcmu_reloc_reg
*
* If the "reg" entry (*pcmu_rp) is relocatable, lookup "assigned-addresses"
* property to fetch corresponding relocated address.
*
* used by: pcmu_map()
*
* return value:
*
* DDI_SUCCESS - on success
* DDI_ME_INVAL - regspec is invalid
*/
int
{
int assign_len, assign_entries, i;
"\tpcmu_reloc_reg fr: %x.%x.%x %x.%x\n",
return (DDI_SUCCESS);
}
/* phys_mid must be 0 regardless space type. XXX-64 bit mem space */
"phys_mid or size_hi not 0\n");
return (DDI_ME_INVAL);
}
return (DDI_ME_INVAL);
}
for (i = 0; i < assign_entries; i++, assign_p++) {
break;
}
}
"\tpcmu_reloc_reg to: %x.%x.%x %x.%x\n",
}
/*
* use "ranges" to translate relocated pci regspec into parent space
*/
int
{
int n;
if (reg_begin > PCI_CONF_HDR_SIZE) {
return (DDI_ME_INVAL);
}
}
continue; /* not the same space type */
}
}
break;
}
}
if (n >= rng_n) {
return (DDI_ME_REGSPEC_RANGE);
}
"\tpcmu_xlate_reg: entry %d new_rp %x.%x %x\n",
return (DDI_SUCCESS);
}
/*
* pcmu_report_dev
*
* This function is called from our control ops routine on a
* DDI_CTLOPS_REPORTDEV request.
*
* The display format is
*
* <name><inst> at <pname><pinst> device <dev> function <func>
*
* where
*
* <name> this device's name property
* <inst> this device's instance number
* <name> parent device's name property
* <inst> parent device's instance number
* <dev> this device's device number
* <func> this device's function number
*/
int
{
if (dip == (dev_info_t *)0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* name_child
*
* This function is called from pcmu_init_child to name a node. It is
* also passed as a callback for node merging functions.
*
* return value: DDI_SUCCESS, DDI_FAILURE
*/
static int
{
int reglen;
char **unit_addr;
uint_t n;
/*
* Set the address portion of the node name based on
* unit-address property, if it exists.
* The interpretation of the unit-address is DD[,F]
* where DD is the device id and F is the function.
*/
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* The unit-address property is does not exist. Set the address
* portion of the node name based on the function and device number.
*/
if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) {
return (DDI_FAILURE);
}
if (func != 0) {
} else {
}
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
int
{
"DDI_CTLOPS_UNINITCHILD: arg=%s%d\n",
return (DDI_SUCCESS);
}
/*
* pcmu_init_child
*
* This function is called from our control ops routine on a
* DDI_CTLOPS_INITCHILD request. It builds and sets the device's
* parent private data area.
*
* used by: pcmu_ctlops()
*
* return value: none
*/
int
{
char name[10];
return (DDI_FAILURE);
"INITCHILD: config regs setup for %s@%s\n",
/*
* Map the child configuration space to for initialization.
* We assume the obp will do the following in the devices
* config space:
*
* Set the latency-timer register to values appropriate
* for the devices on the bus (based on other devices
* MIN_GNT and MAX_LAT registers.
*
* Set the fast back-to-back enable bit in the command
* register if it's supported and all devices on the bus
* have the capability.
*
*/
return (DDI_FAILURE);
}
/*
* Determine the configuration header type.
*/
/*
* If the device has a bus control register then program it
* based on the settings in the command register.
*/
}
return (DDI_SUCCESS);
}
/*
* pcmu_get_reg_set_size
*
* Given a dev info pointer to a pci child and a register number, this
* routine returns the size element of that reg set property.
*
* used by: pcmu_ctlops() - DDI_CTLOPS_REGSIZE
*
* return value: size of reg set on success, zero on error
*/
{
int i;
if (rnumber < 0) {
return (0);
}
/*
* Get the reg property for the device.
*/
return (0);
}
if (rnumber >= (i / (int)sizeof (pci_regspec_t))) {
return (0);
}
return (size);
}
/*
* pcmu_get_nreg_set
*
* Given a dev info pointer to a pci child, this routine returns the
* number of sets in its "reg" property.
*
* used by: pcmu_ctlops() - DDI_CTLOPS_NREGS
*
* return value: # of reg sets on success, zero on error
*/
{
int i, n;
/*
* Get the reg property for the device.
*/
return (0);
}
n = i / (int)sizeof (pci_regspec_t);
return (n);
}
int
{
int fatal = 0;
int nonfatal = 0;
int i;
char buf[FM_MAX_CLASS];
switch (pci_err_tbl[i].reg_bit) {
case PCI_STAT_R_MAST_AB:
aux_msg = "Recieved Master Abort";
/* LINTED fallthrough on case statement */
case PCI_STAT_R_TARG_AB:
aux_msg = "Recieved Target Abort";
if (prierr) {
/*
* piow case are already handled in
* pcmu_pbm_afsr_report()
*/
break;
}
if (caller != PCI_TRAP_CALL) {
/*
* if we haven't come from trap handler
* we won't have an address
*/
fatal++;
}
break;
default:
/*
* dpe on dma write or ta on dma
*/
nonfatal++;
break;
}
"PCI config space:", aux_msg);
}
}
if (fatal)
return (DDI_FM_FATAL);
else if (nonfatal)
return (DDI_FM_NONFATAL);
return (DDI_FM_OK);
}
void
{
int ret = DDI_SUCCESS;
/*
* Save the state of the configuration headers of child
* nodes.
*/
/*
* Not interested in children who are not already
* init'ed. They will be set up in pcmu_init_child().
*/
continue;
}
/*
* Only save config registers if not already saved by child.
*/
SAVED_CONFIG_REGS) == 1) {
continue;
}
/*
* The nexus needs to save config registers. Create a property
* so it knows to restore on resume.
*/
"nexus-saved-config-regs");
if (ret != DDI_PROP_SUCCESS) {
"nexus-saved-config-regs");
}
(void) pci_save_config_regs(cdip);
}
}
void
{
/*
* Restore config registers for children that did not save
* their own registers. Children pwr states are UNKNOWN after
* a resume since it is possible for the PM framework to call
* resume without an actual power cycle. (ie if suspend fails).
*/
/*
* Not interested in children who are not already
* init'ed. They will be set up by pcmu_init_child().
*/
"DDI_RESUME: skipping %s%d not in CF1\n",
continue;
}
/*
* Only restore config registers if saved by nexus.
*/
"nexus-saved-config-regs") == 1) {
(void) pci_restore_config_regs(cdip);
"DDI_RESUME: nexus restoring %s%d config regs\n",
"nexus-saved-config-regs") != DDI_PROP_SUCCESS) {
"nexus-saved-config-regs");
}
}
}
}
#ifdef DEBUG
extern uint64_t pcmu_debug_flags;
{PCMU_DBG_ATTACH, "pcmu_attach"},
{PCMU_DBG_DETACH, "pcmu_detach"},
{PCMU_DBG_MAP, "pcmu_map"},
{PCMU_DBG_A_INTX, "pcmu_add_intx"},
{PCMU_DBG_R_INTX, "pcmu_rem_intx"},
{PCMU_DBG_INIT_CLD, "pcmu_init_child"},
{PCMU_DBG_CTLOPS, "pcmu_ctlops"},
{PCMU_DBG_INTR, "pcmu_intr_wrapper"},
{PCMU_DBG_ERR_INTR, "pcmu_pbm_error_intr"},
{PCMU_DBG_BUS_FAULT, "pcmu_fault"},
{PCMU_DBG_IB, "pcmu_ib"},
{PCMU_DBG_CB, "pcmu_cb"},
{PCMU_DBG_PBM, "pcmu_pbm"},
{PCMU_DBG_OPEN, "pcmu_open"},
{PCMU_DBG_CLOSE, "pcmu_close"},
{PCMU_DBG_IOCTL, "pcmu_ioctl"},
{PCMU_DBG_PWR, "pcmu_pwr"}
};
void
{
char *s = "pcmu unknown";
int i;
int no_rec = (sizeof (pcmu_dflag_strings) /
sizeof (pcmu_dflag_to_str_t));
if (flag & PCMU_DBG_CONT) {
flag &= ~PCMU_DBG_CONT;
cont = 1;
}
for (i = 0; i < no_rec; i++) {
s = pcmu_dflag_strings[i].string;
break;
}
}
if (s && cont == 0) {
ddi_get_instance(dip), s);
}
}
}
#endif