pcibus.c revision 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe
/*
* 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 <fm/libtopo_enum.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <alloca.h>
#include "enumpci.h"
NULL,
};
di_node_t pciex_di_match(const char *);
di_node_t pci_di_match(const char *);
struct tenumr *
_enum_init(void)
{
return (&pci_enumr);
}
int
topo_pci_init(void)
{
/* Devtree = di_init("/", DINFOCACHE); */
if (Devtree == DI_NODE_NIL) {
return (TE_INITFAIL);
}
Promtree = di_prom_init();
if (Promtree == DI_PROM_HANDLE_NIL) {
"PCI enumerator: di_prom_handle_init failed.\n");
return (TE_INITFAIL);
}
return (TE_INITOK);
}
void
topo_pci_fini(void)
{
}
/*
* If this devinfo node came originally from OBP data, we'll have prom
* properties associated with the node where we can find properties of
* interest. We ignore anything after the the first four bytes of the
* property, and interpet those first four bytes as our unsigned
* integer. If we don't find the property or it's not large enough,
* 'val' will remained unchanged and we'll return -1. Otherwise 'val'
* gets updated with the property value and we return 0.
*/
static int
{
continue;
return (0);
}
}
return (-1);
}
/*
* If this devinfo node was added by the PCI hotplug framework it
* doesn't have the PROM properties, but hopefully has the properties
* we're looking for attached directly to the devinfo node. We only
* care about the first four bytes of the property, which we read as
* our unsigned integer. The remaining bytes are ignored. If we
* don't find the property we're looking for, or can't get its value,
* 'val' remains unchanged and we return -1. Otherwise 'val' gets the
* property value and we return 0.
*/
static int
{
continue;
return (0);
}
}
return (-1);
}
/*
* copy_ancestor_prop
* Look for a prop of name 'prop' on an ancestor node in the
* topo tree and duplicate that property and its value on node.
*/
static void
{
const char *value;
return;
while ((p = topo_parent(p)) != NULL)
break;
}
}
/*
* copy_prop
* Look for a prop of name 'prop' on the 'from' node in the
* topo tree and duplicate that property and its value on node.
*/
static void
{
const char *value;
return;
}
static void
{
}
static void
{
char *tmpbuf;
int sz = -1;
continue;
break;
}
}
if (sz < 0) {
if (sz < 0)
continue;
break;
}
}
}
}
}
/*
* Look for a hardware property containing the contents of this node's
* pci express capability register. For now, only look at hardware
* properties and not prom properties. Take the prom handle, though, in
* case we decide we need to check prom properties at a later date.
*/
/*ARGSUSED*/
static int
{
int excap;
return (-1);
return (excap);
}
/*
* Set an EXCAP prop for pci-express capabilities.
*/
static void
{
if (excap < 0)
return;
switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) {
break;
case PCIE_PCIECAP_DEV_TYPE_UP:
break;
break;
break;
break;
break;
}
}
/*
* Get any physical slot name property on this node. The node has to
* declare itself as representing a physical slot number by having a
* .PHYSLOTNUM property. We then look for a .PHYSLOTNAME<slot-#>
* property on the node or an ancestor of the node. If the property
* is found on an ancestor, this routine has the side-effect of
* copying the property to this node.
*/
const char *
{
const char *str;
char *tmpbuf;
char *left;
int physlot;
return (NULL);
return (NULL);
return (str);
}
static void
{
const char *labelval;
const char *platval;
char *tmpbuf;
char *dnpath;
char *dnm;
int devno;
/*
* If it's a root complex, set the pciex capabilities property
*/
/*
* If it's a device node, we pretty much don't add any props
*/
return;
}
/*
* Create a DEVTYPE property as necessary
*/
/*
* Cheat for now and always say the thing is ON
*/
}
/*
* For functions, set LABEL based on a .SLOTNM<devno> property
* in our parent's parent or a .PHYSLOTNAME<slot-#> property
* in an ancestor, or the parent's parent's LABEL, but only if
* LABEL is not already set. Also set PLATFRU and PLATASRU
* based on any .PLATFRU<devno> and .PLATASRU<devno>
* properties from parent's parent.
*/
return;
} else {
}
}
}
/*
* Pecking order for determining the value of PLAT-FRU:
*
* PLAT-FRU already defined by the .topo file, done.
* .PLATFRU<devno> defined, copy that as the value, done.
* LABEL defined (and not inherited), copy that as the value,
* done.
* Copy value from an ancestor.
*/
} else {
else
}
}
}
/*
* fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole
* story, leaving off the device and function number. Chances are if
* devfs doesn't put these on then we'll never see this device as an
* error detector called out in an ereport. Unfortunately, there are
* races and we sometimes do get ereports from devices that devfs
* decides aren't there. For example, the error injector card seems
* to bounce in and out of existence according to devfs. We tack on
* the missing dev and fn here so that the DEV property used to look
* up the topology node is correct.
*/
static void
{
const char *curdev;
char *lastslash;
char *newpath;
int need;
/* Check if there is a DEV prop to fix. */
return;
/*
* We only care about the last component of the dev path. If
* we don't find a slash, something is probably weird and we'll
* just bail.
*/
return;
/*
* If an @ sign is present in the last component, the
* di_devfs_path() result had the device,fn unit-address.
* In that case there's nothing we need do.
*/
return;
if (fnno == 0)
else
need++;
if (fnno == 0)
else
}
static int
{
char *prnm;
int slotsz = -1;
continue;
break;
if (slotsz != sizeof (int))
continue;
break;
}
}
if (slotsz < 0) {
continue;
break;
if (slotsz != sizeof (int))
continue;
break;
}
}
}
if (slotsz < 0) {
(excap & PCIE_PCIECAP_SLOT_IMPL) == 0 ||
return (slotsz);
slotsz = 0;
}
return (slotsz);
}
static void
{
const char *slotnumstr;
char *slotname;
char *tmphcbuf;
char *fmribuf;
char *tmpbuf;
char *left;
int physlot = -1;
int andbit;
/*
* An absolute physical slot number defined in the .topo overrides
* anything we might find in devinfo properties.
*/
/*
* Check for failure to interpret the property
* as a valid slot number, or for a bogus slot
* number.
*/
physlot = -1;
}
/*
* No .topo override, so look for "slot-names" or
* "physical-slot#" properties.
*/
if (physlot < 0 &&
return;
/*
* physical-slot# of zero indicates everything is on-board, ...
*/
if (physlot == 0)
return;
/*
* ... else it's the pciexpress indicator for what slot the child is
* in and so we'll set a property for later use in describing the
* FRU.
*/
/*
* If no .PHYSLOTNUM property is set, we should set one
* so folks coming along later can use that number to find
* the .PHYSLOTNAME<.PHYSLOTNUM> property.
*/
}
/*
* A .PHYSLOTNAME defined in the .topo overrides any
* value we would set. The name is allowed to be on
* any of our ancestors, so we copy it here first.
*/
/*
* No .PHYSLOTNAME<slot-#> is set, so we
* create one, making it the somewhat boring
* "hc:///component=SLOT <slot-#>".
*/
"hc:///component=SLOT %d", physlot);
}
return;
}
if (slotmap == 0)
return;
char *s = slotname;
/*
* Let a slot name defined in the .topo override
* the value from the slot-names property. This
* allows us to fix up mistakes in the OBP (can
* you say chalupa) or elsewise fudge the label
* creatively from the .topo file.
*/
MAXPATHLEN, "hc:///component=%s", s);
}
}
}
}
static int
{
char *pnm;
char *devname;
char *apath;
/*
* Use any attachment point info to indirectly set PLATASRU
* and PLATFRU properties on children of the bus node. We set
* .ASRU# and .FRU# values to be inherited by the appropriate
* children. We allow these to be overridden in the .topo file
* by not setting a property value here if one already exists.
*/
return (DI_WALK_CONTINUE);
}
"hc:///component=%s:%s",
di_minor_name(dim));
}
return (DI_WALK_CONTINUE);
}
static void
{
(void) di_walk_minor(n, "ddi_ctl:attachment_point:pci", 0,
(void *)tn, minorwalkcb);
}
#define IDBUFLEN 13
static const char *
{
char *tmpbuf;
if (device == 0x10000)
if (device != 0x10000) {
}
if (vendor == 0x10000)
if (vendor != 0x10000) {
}
return (idstring);
}
return (NULL);
}
static int
{
return (-1);
return (-1);
return (0);
}
static tnode_t *
{
/*
* We prefer to instance a child node that's uninstanced, so
* it inherits all the right properties.
*/
continue;
if (topo_get_instance_num(cn) < 0) {
break;
}
}
"Expected to set instance %d of a %s topo node. "
}
return (cn);
}
static void
{
const char *topof;
const char *parentcap;
return;
/*
* Get the child's pci express capabilities (if any). We'll later
* convert this to a property on the appropriate topo node.
*/
if (childcap > 0)
/*
* If the child is a root complex, enumerate it as such rather
*/
"complex, but grand-parent topo node "
return;
}
/*
* Beneath a root complex we expect to find a switch,
* bridge or direct link. Whichever it is, it will be
*/
"found pci-express root complex "
"that lacks a " PCIEX_BUS
"child node to instance.\n");
return;
}
return;
}
/*
* Sanity check here: The child of an upstream switch should
* be a downstream switch.
*/
if (childclass != PCI_CLASS_BRIDGE ||
"Devinfo child of UP switch is not a "
"down switch.\n");
return;
}
}
}
/*
* If the parent is an unenumerated bus, do it a favor and set
* an instance number based on the bus defined for this
* device.
*/
topo_get_instance_num(pn) < 0) {
}
return;
NULL)
return;
"the child node would be.\n");
return;
}
return;
return;
/*
* Look for topology information specific to this
* vendor-id & device-id, if any.
*/
}
if (childclass == PCI_CLASS_BRIDGE) {
if (childsubclass != PCI_BRIDGE_PCI) {
return;
}
/*
* What sort of child is this? If there is no
* PCI-express capability or if the capability is a
* bridge to PCI, then children we will enumerate are
* PCI buses.
*/
if (childcap < 0 ||
"no PCI-express capabilities, or a "
"bridge to PCI.\n");
"BUT the topo nodes lacks a "
"child node.\n");
return;
}
} else {
"and has PCI-express capability.\n");
"but the topo nodes lacks a "
"child node.\n");
return;
}
}
/*
* We don't know the instance number of this bus,
* so we'll have to rely on it getting filled in
* later by one of its children.
*/
return;
}
}
void
{
pn = di_child_node(n);
while (pn != DI_NODE_NIL) {
}
}
static di_node_t
{
char *dnpath;
while (pnode != DI_NODE_NIL) {
continue;
break;
}
}
return (pnode);
}
static void
{
/*
* Only do this for PCI_BUS nodes
*/
return;
return;
return;
return;
/*
* The topo node for the hostbridge should inherit the node's
* DRIVER property. The hostbridge is driven by the same
* software as the bus.
*/
}
static void
{
char *dnpath;
while (pnode != DI_NODE_NIL) {
const char *devprop;
continue;
}
}
}
pci_di_match(const char *devproppath)
{
/*
* Search for devinfo nodes for psycho, schizo, or generic
* pci bus and find one that matches the DEV property path
* passed to us.
*/
if (pnode != DI_NODE_NIL)
return (pnode);
if (pnode != DI_NODE_NIL)
return (pnode);
if (pnode != DI_NODE_NIL)
return (pnode);
if (pnode != DI_NODE_NIL)
return (pnode);
return (pnode);
}
pciex_di_match(const char *devproppath)
{
if (pnode != DI_NODE_NIL)
return (pnode);
return (pnode);
}
/*
* Check to see if "node" is the descendant of a topo node that's not
* enumerated, but whose instance number is unambiguous. If it is,
* we can enumerate that puppy because we now know that the ancestor
* is for real.
*/
static void
{
if (topo_get_instance_num(parent) < 0) {
}
}
}
/*
* The enum_pci_bus() routine gets called by topo to set instance
* numbers for all the PCI bus nodes. The enumerator takes care of
* all devices, functions, bridges, and sub-buses beneath the bus
* node as well.
*/
void
{
int express;
/*
* First thing, decide if we're looking for pci-express or
* good old pci. Then orient ourselves within the devinfo
* tree. The static topo info hopefully will have left us an
* orienting clue by providing a DEV property.
*
* Alternatively if there is no DEV, but there's a SCAN
* property, we'll scan for pci buses.
*/
express = 1;
express = 0;
else
return;
"Bus tnode has no DEV or SCAN prop\n");
return;
}
if (express == 0) {
} else {
}
return;
} else {
if (express == 0 &&
"No match found for %s in devinfo.\n", dev);
return;
}
if (express == 1 &&
"No match found for %s in devinfo.\n", dev);
return;
}
}
/*
* We've found ourselves in the devtree. A correctly written
* .topo file will have left the instance number unambiguous
* (a range of exactly one number) and so we'll know and can
* officially establish the instance number of the bus or root
* complex. This creates a new topo node returned to us, with
* children for which we must set instance numbers...
*/
"Unexpected bus instance min %d != max %d.\n",
return;
}
if (express == 0) {
/*
* We represent the hostbridge's PCI bus module as a "device"
* on the bus outside of the range of normal devices.
*/
} else {
/*
* Beneath a root complex we expect to find a switch,
* bridge or direct link. Whichever it is, it will be
*/
"Found pci-express root complex "
"that lacks a " PCIEX_BUS
" child node to instance.\n");
return;
}
}
}
/*
* find_devinfo_childdev()
*
* Search through pci/pci-express devinfo nodes that are a child of
* the parent, looking for ones whose device # matches devno. The
* function is recallable because a device can have multiple
* functions.
*/
{
int cdevno;
if (child != DI_NODE_NIL)
else
while (cn != DI_NODE_NIL) {
continue;
break;
}
return (cn);
}
/*
* The enum_pci_dev() routine gets called by topo to explicitly set
* instance numbers for specific PCI or PCI-Express device nodes.
*/
void
{
const char *dev;
const char *topof;
int fno;
int excap;
/*
* Our parent's parent node should have a DEV property. From
* this we should be able to orient ourselves in the devinfo
* tree.
*/
return;
"PCI enumerator: "
"di_init failed for device ancestor failed.\n");
return;
}
/*
* We've found ourselves in the devtree. A correctly written
* .topo file will have left the instance number unambiguous
* (a range of exactly one number) and so we'll know and can
* officially establish the instance number of the device.
* This creates a new topo node returned to us, with children
* for which we must set instance numbers...
*/
"Unexpected device instance min %d != max %d.\n",
return;
}
if (selfdn == DI_NODE_NIL) {
return;
}
do {
"child node.\n");
return;
}
"child node.\n");
return;
}
/*
* Look for topology information specific to this
* vendor-id & device-id, if any.
*/
}
} while (selfdn != DI_NODE_NIL);
if (fn != DI_NODE_NIL)
}
void
{
/*
* Any enumerations other than buses should have already
* happened at the time the bus was enumerated, so we can just
* return.
*/
}
}