mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2012 lines
54 KiB
2012 lines
54 KiB
/*
|
|
* Copyright (c) 1995,1996 FirePower Systems, Inc.
|
|
* Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
|
|
*
|
|
* $RCSfile: vrtree.c $
|
|
* $Revision: 1.51 $
|
|
* $Date: 1996/06/19 23:13:29 $
|
|
* $Locker: $
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include "veneer.h"
|
|
#include "vrtree.h"
|
|
|
|
extern CHAR *VeneerVersion();
|
|
|
|
/*
|
|
* This table contains some rudimentary plug-n-play-style mappings
|
|
* to assist in assigning the proper Identifiers to device nodes.
|
|
*/
|
|
static struct pnp_info {
|
|
unsigned int port;
|
|
char *id;
|
|
} pnp_data[] = {
|
|
{ 0x278, "LPT3" },
|
|
{ 0x2bc, "LPT4" },
|
|
{ 0x2e8, "COM4" },
|
|
{ 0x2f8, "COM2" },
|
|
{ 0x378, "LPT2" },
|
|
{ 0x3bc, "LPT1" },
|
|
{ 0x3e8, "COM3" },
|
|
{ 0x3f8, "COM1" },
|
|
{ 0x000, "Tooch did this." }
|
|
};
|
|
|
|
|
|
CONFIGURATION_NODE *RootNode;
|
|
STATIC CONFIGURATION_NODE *DisplayNode = 0;
|
|
|
|
STATIC int convert_node(CONFIGURATION_NODE *);
|
|
STATIC CONFIGURATION_NODE *convert_controller(CONFIGURATION_NODE *);
|
|
STATIC CONFIGURATION_NODE *add_new_child(
|
|
CONFIGURATION_NODE *, char *, CONFIGURATION_CLASS, CONFIGURATION_TYPE);
|
|
STATIC int convert_name(CONFIGURATION_NODE *);
|
|
STATIC VOID convert_config(CONFIGURATION_NODE *);
|
|
STATIC VOID convert_cache(PCONFIGURATION_NODE);
|
|
STATIC int convert_PCI_device(PCONFIGURATION_NODE);
|
|
STATIC CONFIGURATION_NODE *convert_SCSI_device(PCONFIGURATION_NODE);
|
|
STATIC CONFIGURATION_NODE *convert_IDE_device(PCONFIGURATION_NODE);
|
|
STATIC VOID convert_system_node(PCONFIGURATION_NODE);
|
|
STATIC VOID update_display_node(PCONFIGURATION_NODE);
|
|
STATIC VOID configure_pci_node(reg *, PCONFIGURATION_NODE );
|
|
|
|
STATIC int default_interrupt_level = 0;
|
|
STATIC int level_equals_vector = FALSE;
|
|
STATIC int default_interrupt_affinity = -1;
|
|
STATIC int default_affinity = -1;
|
|
STATIC int init_key_array[64];
|
|
STATIC int *key_array = init_key_array;
|
|
|
|
/*
|
|
* Traverse the OF tree. For each node, figure out what it corresponds
|
|
* to in an ARC tree and construct the Component and resource
|
|
* description data structures. Call this initially with node = 0
|
|
* so peer() finds the root node. See 6.3.2.2.
|
|
*
|
|
* At each node, build a CONFIGURATION_NODE and attempt to convert the
|
|
* node to an ARC component. If this conversion fails, free the
|
|
* CONFIGURATION_NODE and move on, continuing to pass "here." Otherwise
|
|
* move on, and pass "here" = "newlink." This way unconverted nodes
|
|
* are pruned out of the tree.
|
|
*/
|
|
|
|
void
|
|
walk_obp(
|
|
phandle ph,
|
|
CONFIGURATION_NODE *here,
|
|
CONFIGURATION_NODE *parent,
|
|
CONFIGURATION_NODE *peer)
|
|
{
|
|
phandle newph;
|
|
CONFIGURATION_NODE *newlink;
|
|
int *saved_key_array;
|
|
extern int level; // for debug output
|
|
|
|
//VRASSERT((parent) || ((parent == 0) && (here == 0) && (peer == 0)));
|
|
debug(VRDBG_TREE, "\n");
|
|
debug(VRDBG_TREE, "walk_obp: phandle 0x%x (%d)\n", ph, level);
|
|
debug(VRDBG_TREE, "walk_obp:\there 0x%x parent 0x%x peer 0x%x\n",
|
|
here, parent, peer);
|
|
|
|
if (newph = OFChild(ph)) {
|
|
//
|
|
// Here we descend to a new level of the tree. Increment "level"
|
|
// so that debugging printouts reflect the level of the tree,
|
|
// and allocate a new "key_array" since counts reset at each
|
|
// level of the tree. See convert_node() for the use of
|
|
// key_array.
|
|
//
|
|
//
|
|
level++;
|
|
saved_key_array = key_array;
|
|
key_array = (int *) zalloc(64 * sizeof(int)); //"Enough" slots.
|
|
newlink = new(CONFIGURATION_NODE);
|
|
newlink->OfPhandle = newph;
|
|
debug(VRDBG_TREE, "walk_obp:\tNew Child node: 0x%x\n", newlink);
|
|
|
|
//
|
|
// If there's already an ARC Node "HERE", then set the newlink's
|
|
// parent to point to the node "HERE".
|
|
//
|
|
if (here) {
|
|
newlink->Parent = here;
|
|
} else {
|
|
newlink->Parent = parent;
|
|
}
|
|
if (convert_node(newlink)) {
|
|
if (here) {
|
|
if (here->Child == 0) {
|
|
here->Child = newlink;
|
|
walk_obp(newph, newlink, here, 0);
|
|
} else {
|
|
CONFIGURATION_NODE *tmplink;
|
|
debug(VRDBG_TREE, "walk_obp: newlink = here->Child(0x%x)\n",
|
|
here->Child);
|
|
tmplink = here->Child;
|
|
while (tmplink->Peer) {
|
|
tmplink = tmplink->Peer;
|
|
}
|
|
|
|
tmplink->Peer = newlink;
|
|
VRDBG(VRDBG_TREE, vr_dump_config_node(tmplink));
|
|
walk_obp(newph, newlink, here, 0);
|
|
}
|
|
} else if (peer) {
|
|
newlink->Peer = peer->Peer;
|
|
peer->Peer = newlink;
|
|
walk_obp(newph, newlink, parent, newlink);
|
|
while (peer->Peer) {
|
|
peer = peer->Peer;
|
|
}
|
|
} else if (parent) {
|
|
newlink->Peer = parent->Child;
|
|
parent->Child = newlink;
|
|
walk_obp(newph, newlink, here, 0);
|
|
peer = newlink;
|
|
while (peer->Peer) {
|
|
peer = peer->Peer;
|
|
}
|
|
}
|
|
} else {
|
|
debug(VRDBG_TREE, "walk_obp: FREE CHILD NODE 0x%x\n", newlink);
|
|
free((char *)newlink);
|
|
if (here) {
|
|
walk_obp(newph, 0, here, 0);
|
|
} else {
|
|
walk_obp(newph, 0, parent, peer);
|
|
}
|
|
}
|
|
//
|
|
// Ascend: restore level and key_array.
|
|
//
|
|
level--;
|
|
key_array = saved_key_array;
|
|
}
|
|
|
|
if (newph = OFPeer(ph)) {
|
|
newlink = new(CONFIGURATION_NODE);
|
|
debug(VRDBG_TREE, "walk_obp:\tnew Peer node: 0x%x\n", newlink);
|
|
if (ph == 0) {
|
|
RootNode = newlink;
|
|
}
|
|
newlink->OfPhandle = newph;
|
|
newlink->Parent = parent;
|
|
if (convert_node(newlink)) {
|
|
if (here) {
|
|
if (here->Peer == 0) {
|
|
here->Peer = newlink;
|
|
} else {
|
|
CONFIGURATION_NODE *tmplink;
|
|
debug(VRDBG_TREE, "walk_obp: newlink = here->Peer(0x%x)\n",
|
|
here->Peer);
|
|
tmplink = here->Peer;
|
|
while (tmplink->Peer) {
|
|
tmplink = tmplink->Peer;
|
|
}
|
|
tmplink->Peer = newlink;
|
|
VRDBG(VRDBG_TREE, vr_dump_config_node(tmplink));
|
|
}
|
|
} else {
|
|
if (peer) {
|
|
newlink->Peer = peer->Peer;
|
|
peer->Peer = newlink;
|
|
} else {
|
|
if (parent) {
|
|
newlink->Peer = parent->Child;
|
|
parent->Child = newlink;
|
|
}
|
|
}
|
|
}
|
|
walk_obp(newph, newlink, parent, newlink);
|
|
} else {
|
|
debug(VRDBG_TREE, "walk_obp: FREE PEER NODE 0x%x\n", newlink);
|
|
free((char *)newlink);
|
|
if (here) {
|
|
walk_obp(newph, 0, parent, here);
|
|
} else {
|
|
walk_obp(newph, 0, parent, peer);
|
|
}
|
|
}
|
|
}
|
|
debug(VRDBG_TREE, "walk_obp =====================> exit(%d)\n",level);
|
|
}
|
|
|
|
STATIC int
|
|
convert_node(CONFIGURATION_NODE *node)
|
|
{
|
|
phandle ph = node->OfPhandle;
|
|
PCONFIGURATION_COMPONENT Component = &node->Component;
|
|
PCHAR arcid;
|
|
LONG key=-1;
|
|
|
|
debug(VRDBG_TREE, "convert_node: node(0x%x) Begin ....\n", node);
|
|
node->ComponentName = get_str_prop(ph, "name", ALLOC);
|
|
if (node->ComponentName == 0) {
|
|
debug(VRDBG_TREE, "convert_node: NULL ComponentName. return FALSE\n");
|
|
return FALSE;
|
|
}
|
|
if (convert_name(node) == 0) {
|
|
debug(VRDBG_TREE, "convert_node: convert_name returned 0...\n", node);
|
|
return FALSE;
|
|
}
|
|
Component->Revision = ARC_REVISION;
|
|
Component->Version = ARC_VERSION;
|
|
Component->AffinityMask = default_affinity;
|
|
|
|
switch(Component->Class) {
|
|
case ProcessorClass:
|
|
break;
|
|
case CacheClass:
|
|
convert_cache(node);
|
|
break;
|
|
|
|
case ControllerClass:
|
|
Component->Key = key_array[Component->Type]++;
|
|
if((node = convert_controller(node)) == 0 ) {
|
|
debug(VRDBG_TEST|VRDBG_TREE,
|
|
"Convert_node: failed convert_controller, return FALSE\n");
|
|
return(FALSE);
|
|
}
|
|
convert_config(node);
|
|
break;
|
|
|
|
default:
|
|
Component->Key = key_array[Component->Type]++;
|
|
convert_config(node);
|
|
break;
|
|
}
|
|
|
|
if (arcid = get_str_prop(ph, "arc-identifier", ALLOC)) {
|
|
node->Component.Identifier = arcid;
|
|
node->Component.IdentifierLength = strlen(arcid) + 1;
|
|
}
|
|
|
|
if ((key = get_int_prop(ph, "arc-key")) != -1) {
|
|
node->Component.Key = key;
|
|
}
|
|
debug(VRDBG_TREE|VRDBG_ENTRY,
|
|
"convert_node: ... returning true\n");
|
|
return(TRUE);
|
|
}
|
|
|
|
STATIC int
|
|
convert_name(CONFIGURATION_NODE *node)
|
|
{
|
|
char *name = node->ComponentName;
|
|
char *type = get_str_prop(node->OfPhandle, "device_type", NOALLOC);
|
|
char **id = &node->Component.Identifier;
|
|
char *cp, *String=0;
|
|
int result = 1;
|
|
static int ncpus = 0;
|
|
|
|
//
|
|
// The conversion is based upon device_type, or if that fails,
|
|
// name. As a first approximation the ARC node's Identifier, if
|
|
// converted, is set to the OFW node's name property.
|
|
// This is OK, as later in the process the "arc-identifier"
|
|
// property can override the Identifier set here. See above.
|
|
//
|
|
|
|
debug(VRDBG_TREE, "convert_name: node(0x%x) is type %s \n",
|
|
node, TypeNames[node->Component.Type]);
|
|
*id = name;
|
|
if (cp = index(name, ',')) {
|
|
*cp = '-';
|
|
}
|
|
|
|
//
|
|
// If Parent == 0, we can assume this is the root node.
|
|
//
|
|
if (node->Parent == 0) {
|
|
node->Component.Class = SystemClass;
|
|
node->Component.Type = ArcSystem;
|
|
|
|
//
|
|
// OFW, name is Company, Model
|
|
//
|
|
String = get_str_prop(node->OfPhandle, "name", ALLOC);
|
|
node->Component.Identifier = index(String, ',');
|
|
if (node->Component.Identifier == NULL) {
|
|
node->Component.Identifier = String;
|
|
} else {
|
|
node->Component.Identifier++;
|
|
}
|
|
|
|
debug(VRDBG_TEST, "convert_name: node %x (%s)", node, name);
|
|
debug(VRDBG_TEST, "convert_name: OFW String (%s)\n", String);
|
|
debug(VRDBG_TEST, "convert_name: Identifier (%s)\n",
|
|
node->Component.Identifier);
|
|
goto found;
|
|
}
|
|
|
|
if (type == 0) {
|
|
goto just_name;
|
|
}
|
|
|
|
//
|
|
// First try to match on device-type.
|
|
// This is enough in many cases.
|
|
//
|
|
if (strcmp(type, "cpu") == 0) {
|
|
node->Component.Class = ProcessorClass;
|
|
node->Component.Type = CentralProcessor;
|
|
node->Component.Key = get_int_prop(node->OfPhandle, "reg");
|
|
if (node->Component.Key == -1) {
|
|
node->Component.Key = ncpus++;
|
|
}
|
|
cp = index(name, '-') + 1;
|
|
*id = (char *) zalloc(13);
|
|
strcpy(*id, "PowerPC(");
|
|
strcat(*id, cp);
|
|
strcat(*id, ")");
|
|
if (get_int_prop(node->OfPhandle, "i-cache-size")) {
|
|
convert_cache(add_new_child(node,
|
|
"cache", CacheClass, PrimaryIcache));
|
|
}
|
|
|
|
//
|
|
// The following block is to support old FirePower ROMs.
|
|
// If version 510 ROMs are ever desupported, this block
|
|
// can be deleted.
|
|
//
|
|
|
|
if (strcmp(
|
|
get_str_prop(OFParent(node->OfPhandle), "name", NOALLOC),
|
|
"cpus") != 0) {
|
|
|
|
//
|
|
// This is a 510 rom: it builds a single processor
|
|
// node even if it's an MP machine. We need to
|
|
// probe and report all CPUs ourselves.
|
|
// Since we know 501-rom-equipped machines have
|
|
// 1 or 2 processors, the job isn't that bad:
|
|
// we look at mailbox[1] and see if the contents
|
|
// are equal to "processor ready" (1). If so,
|
|
// we are dual-proc.
|
|
//
|
|
|
|
PULONG mbox = (PULONG) 0x2f88;
|
|
CONFIGURATION_NODE *peer;
|
|
|
|
if (*mbox == 1) {
|
|
peer = new(CONFIGURATION_NODE);
|
|
bcopy((PCHAR) node, (PCHAR) peer, sizeof(CONFIGURATION_NODE));
|
|
node->Peer = peer;
|
|
peer->Component.Revision = ARC_REVISION;
|
|
peer->Component.Version = ARC_VERSION;
|
|
peer->Component.Key = ncpus++;
|
|
peer->Component.AffinityMask = 1 << peer->Component.Key;
|
|
peer->Child = 0;
|
|
peer->Component.IdentifierLength =
|
|
strlen(peer->Component.Identifier) + 1;
|
|
convert_cache(add_new_child(peer,
|
|
"cache", CacheClass, PrimaryIcache));
|
|
}
|
|
}
|
|
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "cache") == 0) {
|
|
//
|
|
// What does the cache architecture of the system
|
|
// look like? OF reports processor caches in the cpu node,
|
|
// so that case is handled above. This must be a discrete
|
|
// off-chip cache of some kind. Is it bound to a particular
|
|
// processor, or is it a system-wide cache, or what?
|
|
//
|
|
// PReP machines call for a "transparent" Level-2 cache.
|
|
// Currently, these should be reported to NT as children
|
|
// of the root node--thus this code. IT IS CRUCIAL that
|
|
// this routine return FALSE, because we want to explicitly
|
|
// build a child of the root node, and we do NOT want to
|
|
// allow a node to be built in our present location.
|
|
//
|
|
// XXX - This may need to be re-examined in a future release
|
|
// as system architectures develop.
|
|
//
|
|
|
|
PCONFIGURATION_NODE newnode;
|
|
|
|
newnode = add_new_child(RootNode, "cache", CacheClass, SecondaryCache);
|
|
newnode->OfPhandle = node->OfPhandle;
|
|
convert_cache(newnode);
|
|
debug(VRDBG_TREE,"convert_node: node %s (0x%x) has new parent: ROOT.\n",
|
|
newnode->ComponentName, newnode);
|
|
return (0);
|
|
|
|
} else if (strcmp(type, "pci") == 0) {
|
|
node->Component.Class = AdapterClass;
|
|
node->Component.Type = MultiFunctionAdapter;
|
|
node->ComponentName = "multi";
|
|
*id = "PCI";
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "isa") == 0) {
|
|
node->Component.Class = AdapterClass;
|
|
node->Component.Type = MultiFunctionAdapter;
|
|
node->ComponentName = "multi";
|
|
*id = "ISA";
|
|
goto found;
|
|
|
|
} else if (strncmp(type, "scsi", 4) == 0) {
|
|
node->Component.Class = AdapterClass;
|
|
node->Component.Type = ScsiAdapter;
|
|
node->ComponentName = "scsi";
|
|
String = get_str_prop(node->OfPhandle, "model", NOALLOC);
|
|
debug(VRDBG_TEST, "String(name)is ...%s:", String);
|
|
*id = (char *) zalloc(16);
|
|
if(strcmp(String, "NCR,53C810") == 0) {
|
|
*id = "NCRC810";
|
|
debug(VRDBG_TEST|VRDBG_SCSI,
|
|
"nodeID =......%s:\n", node->Component.Identifier);
|
|
goto found;
|
|
}
|
|
if(strcmp(String, "AMD 53C794") == 0) {
|
|
*id = "AMD53C974";
|
|
debug(VRDBG_TEST|VRDBG_SCSI,
|
|
"nodeID =......%s:\n", node->Component.Identifier);
|
|
goto found;
|
|
}
|
|
if (strncmp(String, "ADPT,AIC-78",11) == 0) {
|
|
*id = "AIC78XX";
|
|
debug(VRDBG_TEST|VRDBG_SCSI,
|
|
"nodeID =......%s:\n", node->Component.Identifier);
|
|
goto found;
|
|
}
|
|
|
|
*id = "UNKNOWN SCSI";
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "ide") == 0) {
|
|
|
|
node->Component.Class = AdapterClass;
|
|
node->Component.Type = ScsiAdapter;
|
|
node->ComponentName = "scsi";
|
|
node->Component.Flags.Input = 1;
|
|
node->Component.Flags.Output = 1;
|
|
*id = "IDE";
|
|
goto found;
|
|
|
|
//
|
|
// Don't change the names on controllers yet. They all
|
|
// get treated again in convert_controller() to build
|
|
// their child peripheral nodes, etc. Leave the current
|
|
// names intact so we can distinguish between e.g.
|
|
// hard disk and floppy.
|
|
//
|
|
} else
|
|
if (strcmp(type, "block") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
if (strcmp(name, "disk") == 0) {
|
|
node->Component.Type = DiskController;
|
|
} else
|
|
if (strcmp(name, "floppy") == 0) {
|
|
node->Component.Type = DiskController;
|
|
} else
|
|
if (strcmp(name, "cdrom") == 0) {
|
|
node->Component.Type = CdromController;
|
|
} else
|
|
if (strcmp(name, "worm") == 0) {
|
|
node->Component.Type = WormController;
|
|
} else {
|
|
node->Component.Type = OtherController;
|
|
}
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "byte") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = TapeController;
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "display") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = DisplayController;
|
|
String = get_str_prop(node->OfPhandle, "model", ALLOC);
|
|
if (String == NULL) {
|
|
String = get_str_prop(node->OfPhandle, "name", ALLOC);
|
|
}
|
|
if (strcmp(String,"FirePower,Powerized_Display" ) == 0) {
|
|
node->Component.Identifier = "Powerized Graphics";
|
|
} else {
|
|
node->Component.Identifier = capitalize(String);
|
|
}
|
|
if (String == NULL) {
|
|
node->Component.Identifier = "VGA";
|
|
}
|
|
|
|
update_display_node(node);
|
|
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "network") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = NetworkController;
|
|
|
|
//
|
|
// The stuff that follows is legacy support.
|
|
// See the comments for "I8042PRT" below.
|
|
//
|
|
String = get_str_prop(node->OfPhandle, "name", NOALLOC);
|
|
debug(VRDBG_TEST, "NetWork String(name)is ...%s:", String);
|
|
*id = (char *) zalloc(16);
|
|
if(strcmp(String, "pci1011,2") == 0) {
|
|
*id = "DC21x4";
|
|
goto found;
|
|
}
|
|
if(strcmp(String, "AMD,79c970") == 0) {
|
|
*id = "AMD79C970";
|
|
goto found;
|
|
}
|
|
*id = "UNKNOWN NETWORK";
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "serial") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = SerialController;
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "parallel") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = ParallelController;
|
|
goto found;
|
|
|
|
//
|
|
// For both keyboard and mouse below, the Identifier really
|
|
// should come from an "arc-identifier" property. Alas,
|
|
// there are machines in the field with ROM versions that
|
|
// don't have the arc-identifier property, so this legacy
|
|
// code will have to stay here forever.
|
|
//
|
|
|
|
} else if (strcmp(type, "keyboard") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = KeyboardController;
|
|
*id = get_str_prop(OFParent(node->OfPhandle), "name", ALLOC);
|
|
if (strcmp(*id, "8042") == 0) {
|
|
free(*id);
|
|
*id = "I8042PRT";
|
|
}
|
|
goto found;
|
|
|
|
} else if (strcmp(type, "mouse") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = PointerController;
|
|
*id = get_str_prop(OFParent(node->OfPhandle), "name", ALLOC);
|
|
if (strcmp(*id, "8042") == 0) {
|
|
free(*id);
|
|
*id = "I8042PRT";
|
|
}
|
|
goto found;
|
|
}
|
|
|
|
just_name:
|
|
|
|
//
|
|
// Device-type wasn't enough. We'll try matching
|
|
// on name now.
|
|
//
|
|
if (strcmp(name, "audio") == 0) {
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = AudioController;
|
|
goto found;
|
|
|
|
} else if (strcmp(name, "memory") == 0) {
|
|
node->Component.Class = MemoryClass;
|
|
node->Component.Type = SystemMemory;
|
|
//
|
|
// "memory" nodes have two properties of interest:
|
|
// a "reg" prop which describes actual installed memory,
|
|
// and an "available" prop which describes the memory
|
|
// that hasn't been allocated. We'll pick up the
|
|
// reg prop later, in convert_config().
|
|
//
|
|
goto found;
|
|
|
|
} else if (strcmp(node->Parent->Component.Identifier, "PCI") == 0) {
|
|
//
|
|
// This is presumably a PCI expansion card, but without
|
|
// an FCode expansion ROM.
|
|
//
|
|
if (convert_PCI_device(node) == 0) {
|
|
result = 0;
|
|
}
|
|
goto found;
|
|
|
|
} else {
|
|
//
|
|
// Else what?
|
|
//
|
|
debug(VRDBG_TREE, "convert_name: node '%s' (0x%x) is unmatched!\n",
|
|
name, node);
|
|
return (0);
|
|
}
|
|
found:
|
|
//
|
|
// NOTE: the IdentifierLength *includes* the null terminator.
|
|
//
|
|
|
|
if (*id) {
|
|
if (*id == name) {
|
|
char *newid = zalloc(strlen(*id) + 1);
|
|
strcpy(newid, *id);
|
|
*id = newid;
|
|
}
|
|
node->Component.IdentifierLength =
|
|
strlen(*id) + 1;
|
|
}
|
|
debug(VRDBG_TREE,
|
|
"convert_name: node %s (%x) type '%s' is Class %s Type %s ID: %s\n",
|
|
name, node, type ? type : "",
|
|
ClassNames[node->Component.Class], TypeNames[node->Component.Type],
|
|
node->Component.IdentifierLength ? node->Component.Identifier : "");
|
|
return (result);
|
|
}
|
|
|
|
STATIC CONFIGURATION_NODE *
|
|
convert_controller(CONFIGURATION_NODE *node)
|
|
{
|
|
phandle ph = node->OfPhandle;
|
|
PCONFIGURATION_COMPONENT Component = &node->Component;
|
|
char *name = node->ComponentName;
|
|
|
|
debug(VRDBG_TREE, "convert_controller: node(0x%x) is type %s \n",
|
|
node, TypeNames[node->Component.Type]);
|
|
if (OFChild(ph)) {
|
|
debug(VRDBG_TREE, "Controller node %x '%s' already has a child (%s)!\n",
|
|
Component, name,get_str_prop(OFChild(ph), "name", NOALLOC));
|
|
VRDBG(VRDBG_TREE, vr_dump_config_node(node));
|
|
return(0);
|
|
}
|
|
|
|
switch (Component->Type) {
|
|
|
|
case DiskController:
|
|
if (strcmp(name, "disk") == 0) {
|
|
(void) add_new_child(node, "rdisk",
|
|
PeripheralClass, DiskPeripheral);
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
} else if (strcmp(name, "floppy") == 0) {
|
|
(void) add_new_child(node, "fdisk",
|
|
PeripheralClass, FloppyDiskPeripheral);
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
node->Child->Component.Flags.Removable = 1;
|
|
} else
|
|
warn("What is this disk controller '%s'?\n", name);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
break;
|
|
|
|
case TapeController:
|
|
node->ComponentName = "tape";
|
|
(void) add_new_child(node, "tape",
|
|
PeripheralClass, TapePeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
node->Child->Component.Flags.Removable = 1;
|
|
break;
|
|
|
|
case CdromController:
|
|
node->ComponentName = "cdrom";
|
|
(void) add_new_child(node, "fdisk",
|
|
PeripheralClass, FloppyDiskPeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.ReadOnly = 1;
|
|
Component->Flags.Removable = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.ReadOnly = 1;
|
|
node->Child->Component.Flags.Removable = 1;
|
|
break;
|
|
|
|
case WormController:
|
|
node->ComponentName = "worm";
|
|
(void) add_new_child(node, "rdisk",
|
|
PeripheralClass, DiskPeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
node->Child->Component.Flags.Removable = 1;
|
|
break;
|
|
|
|
case SerialController:
|
|
node->ComponentName = "serial";
|
|
(void) add_new_child(node, "line",
|
|
PeripheralClass, LinePeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
Component->Flags.ConsoleIn = 1;
|
|
Component->Flags.ConsoleOut = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
node->Child->Component.Flags.ConsoleIn = 1;
|
|
node->Child->Component.Flags.ConsoleOut = 1;
|
|
break;
|
|
|
|
case NetworkController:
|
|
node->ComponentName = "net";
|
|
(void) add_new_child(node, "network",
|
|
PeripheralClass, NetworkPeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
break;
|
|
|
|
case DisplayController:
|
|
node->ComponentName = "video";
|
|
(void) add_new_child(node, "monitor",
|
|
PeripheralClass, MonitorPeripheral);
|
|
Component->Flags.Output = 1;
|
|
Component->Flags.ConsoleOut = 1;
|
|
node->Child->Component.Identifier = "1024x768";
|
|
node->Child->Component.IdentifierLength = 9;
|
|
node->Child->Component.Flags.Output = 1;
|
|
node->Child->Component.Flags.ConsoleOut = 1;
|
|
break;
|
|
|
|
case ParallelController:
|
|
node->ComponentName = "par";
|
|
(void) add_new_child(node, "print",
|
|
PeripheralClass, PrinterPeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
break;
|
|
|
|
case PointerController:
|
|
node->ComponentName = "point";
|
|
(void) add_new_child(node, "pointer",
|
|
PeripheralClass, PointerPeripheral);
|
|
Component->Flags.Input = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Identifier = MOUSE_IDENTIFIER;
|
|
node->Child->Component.IdentifierLength =
|
|
strlen(MOUSE_IDENTIFIER) + 1;
|
|
break;
|
|
|
|
case KeyboardController:
|
|
node->ComponentName = "key";
|
|
(void) add_new_child(node, "keyboard",
|
|
PeripheralClass, KeyboardPeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.ConsoleIn = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.ConsoleIn = 1;
|
|
node->Child->Component.Identifier = KBD_IDENTIFIER;
|
|
node->Child->Component.IdentifierLength =
|
|
strlen(KBD_IDENTIFIER) + 1;
|
|
break;
|
|
|
|
case AudioController:
|
|
node->ComponentName = "other";
|
|
(void) add_new_child(node, "other",
|
|
PeripheralClass, OtherPeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
break;
|
|
|
|
case OtherController:
|
|
node->ComponentName = "other";
|
|
(void) add_new_child(node, "other",
|
|
PeripheralClass, OtherPeripheral);
|
|
Component->Flags.Input = 1;
|
|
Component->Flags.Output = 1;
|
|
node->Child->Component.Flags.Input = 1;
|
|
node->Child->Component.Flags.Output = 1;
|
|
break;
|
|
|
|
default:
|
|
warn("Unknown controller class %d type %d\n",
|
|
Component->Class, Component->Type);
|
|
break;
|
|
}
|
|
//
|
|
// NOTE: the IdentifierLength *includes* the null terminator.
|
|
//
|
|
if (node->Component.Identifier) {
|
|
node->Component.IdentifierLength =
|
|
strlen(node->Component.Identifier) + 1;
|
|
}
|
|
|
|
debug(VRDBG_TREE, "convert_controller: node %x has parent %x of Type %s\n",
|
|
node, node->Parent, TypeNames[node->Parent->Component.Type]);
|
|
|
|
//
|
|
// Finally, check to see if this is a child of a ScsiAdapter.
|
|
// If it is, we may have to probe the bus.
|
|
//
|
|
|
|
if (node->Parent->Component.Type == ScsiAdapter) {
|
|
if (strcmp(node->Parent->Component.Identifier, "IDE") == 0) {
|
|
return (convert_IDE_device(node));
|
|
} else {
|
|
return (convert_SCSI_device(node));
|
|
}
|
|
}
|
|
|
|
return (node);
|
|
}
|
|
|
|
/*
|
|
* We found a leaf node. In classical OF this would be sufficient; i.e.
|
|
* this node would contain the methods to drive the device and the properties
|
|
* that describe the device. But in the ARC world, this node corresponds
|
|
* to a ControllerClass Component, which is expected to have a PeripheralClass
|
|
* Component that describes the actual device.
|
|
* In this function we take an existing "Controller" node and add a
|
|
* "Peripheral" node as a child.
|
|
*/
|
|
STATIC CONFIGURATION_NODE *
|
|
add_new_child(
|
|
CONFIGURATION_NODE *parent,
|
|
char *name,
|
|
CONFIGURATION_CLASS class,
|
|
CONFIGURATION_TYPE type
|
|
)
|
|
{
|
|
PCONFIGURATION_NODE child;
|
|
PCONFIGURATION_COMPONENT Component;
|
|
|
|
debug(VRDBG_TREE,
|
|
"add_new_child: parent %s(0x%x) will get child %s Type %s\n",
|
|
parent->ComponentName, parent, name, TypeNames[type]);
|
|
child = new(CONFIGURATION_NODE);
|
|
child->Parent = parent;
|
|
debug(VRDBG_TREE, "add_new_child: add child (0x%x) to node 0x%x\n",
|
|
child, child->Parent);
|
|
if (parent->Child != NULL) {
|
|
PCONFIGURATION_NODE node = parent->Child;
|
|
while (node->Peer) {
|
|
node = node->Peer;
|
|
}
|
|
node->Peer = child;
|
|
} else {
|
|
parent->Child = child;
|
|
}
|
|
child->ComponentName = name;
|
|
child->OfPhandle = parent->OfPhandle;
|
|
Component = &child->Component;
|
|
Component->Class = class;
|
|
Component->Type = type;
|
|
Component->Revision = ARC_REVISION;
|
|
Component->Version = ARC_VERSION;
|
|
Component->AffinityMask = default_affinity;
|
|
Component->Key = key_array[Component->Type]++;
|
|
VRDBG(VRDBG_TREE, vr_dump_config_node(child));
|
|
|
|
return (child);
|
|
}
|
|
|
|
/*
|
|
* A PCI device without an FCode ROM may yet have enough useful
|
|
* properties encoded in configuration space to make a reasonable
|
|
* guess about its device type, etc.
|
|
*/
|
|
STATIC int
|
|
convert_PCI_device(PCONFIGURATION_NODE node)
|
|
{
|
|
phandle ph = node->OfPhandle;
|
|
int class_code, base_class, sub_class, prog_class;
|
|
|
|
debug(VRDBG_TREE, "Converting PCI device '%s'\n", node->ComponentName);
|
|
class_code = get_int_prop(ph, "class-code");
|
|
debug(VRDBG_TREE, "PCI node class = %x\n", class_code);
|
|
if (class_code == -1) {
|
|
/* Hopeless */
|
|
return (0);
|
|
}
|
|
base_class = (class_code >> 16) & 0xff;
|
|
sub_class = (class_code >> 8) & 0xff;
|
|
prog_class = class_code & 0xff;
|
|
|
|
switch (base_class) {
|
|
case 0:
|
|
node->Component.Class = ControllerClass;
|
|
if (sub_class == 1 && prog_class == 0) {
|
|
node->Component.Type = DisplayController;
|
|
update_display_node(node);
|
|
} else {
|
|
node->Component.Type = OtherController;
|
|
}
|
|
goto ok;
|
|
|
|
case 1:
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = DiskController;
|
|
switch (sub_class) {
|
|
case 0: node->Component.Class = AdapterClass;
|
|
node->Component.Type = ScsiAdapter;
|
|
node->ComponentName = "scsi";
|
|
(void) add_new_child(node, "disk",
|
|
ControllerClass, DiskController);
|
|
(void) add_new_child(node, "tape",
|
|
ControllerClass, TapeController);
|
|
break;
|
|
case 1: node->ComponentName = "multi"; // IDE, actually
|
|
break;
|
|
case 2: node->ComponentName = "floppy";
|
|
break;
|
|
case 3: node->ComponentName = "ipi";
|
|
break;
|
|
default: node->ComponentName = "other";
|
|
break;
|
|
}
|
|
goto ok;
|
|
|
|
case 2:
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = NetworkController;
|
|
goto ok;
|
|
|
|
case 3:
|
|
node->Component.Class = ControllerClass;
|
|
|
|
#ifdef rev1_30
|
|
node->Component.Type = DisplayController;
|
|
#else
|
|
if (sub_class == 0 && prog_class == 0) {
|
|
node->Component.Type = DisplayController;
|
|
update_display_node(node);
|
|
} else {
|
|
node->Component.Type = OtherController;
|
|
}
|
|
|
|
#endif
|
|
goto ok;
|
|
|
|
case 4:
|
|
node->Component.Class = ControllerClass;
|
|
switch (sub_class) {
|
|
case 0: node->Component.Type = DisplayController;
|
|
goto ok;
|
|
case 1: node->Component.Type = AudioController;
|
|
goto ok;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
//
|
|
// What are we to do about memory cards?
|
|
//
|
|
break;
|
|
|
|
case 6:
|
|
node->Component.Class = AdapterClass;
|
|
if (sub_class == 2) {
|
|
node->Component.Type = EisaAdapter;
|
|
node->ComponentName = "eisa";
|
|
} else {
|
|
node->Component.Type = MultiFunctionAdapter;
|
|
node->ComponentName = "multi";
|
|
}
|
|
goto ok;
|
|
|
|
}
|
|
|
|
//
|
|
// What is this thing?
|
|
//
|
|
node->Component.Class = ControllerClass;
|
|
node->Component.Type = OtherController;
|
|
node->ComponentName = "other";
|
|
ok:
|
|
if( VrDebug & VRDBG_TREE ) {
|
|
DisplayConfig(&node->Component);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* ScsiAdapter nodes have some special rules. The child controllers' Key
|
|
* values are the SCSI target ID, not the instance, and the child
|
|
* controllers' Identifiers are specified to be the concatenation of
|
|
* the vendor and product name fields as returned from INQUIRY.
|
|
*
|
|
* Worse news: SCSI devices may be wildcarded, so we've got to probe
|
|
* the whole bus here if we find a wildcard node.
|
|
*
|
|
* As an optimization, record the fact that we've probed the bus
|
|
* so we need probe only once. This eliminates duplicate probes as
|
|
* the firmware customarily reports both a disk and tape wildcard.
|
|
* The list of probed nodes is an array of "sufficient" size.
|
|
* Yes, I know.
|
|
*/
|
|
|
|
STATIC CONFIGURATION_NODE *
|
|
convert_SCSI_device(PCONFIGURATION_NODE node)
|
|
{
|
|
PCONFIGURATION_NODE newnode, parent=node->Parent;
|
|
CONFIGURATION_TYPE type = node->Component.Type, newtype;
|
|
phandle ph = node->OfPhandle;
|
|
phandle parentph = parent->OfPhandle;
|
|
static PCONFIGURATION_NODE done_list[32] = { 0 };
|
|
reg *regp;
|
|
char *path;
|
|
int i;
|
|
ihandle ih;
|
|
UCHAR inq[] = { 0x12, 0, 0, 0, 0xff, 0 };
|
|
ULONG res[2];
|
|
UCHAR *inq_data;
|
|
static int lock = 0;
|
|
int max_scsi_target = 8, scsi_host_id = 7;
|
|
int tmp_scsi_host_id = -1;
|
|
|
|
|
|
|
|
if (lock++) {
|
|
--lock;
|
|
return(0);
|
|
}
|
|
|
|
debug(VRDBG_ENTRY|VRDBG_TREE|VRDBG_SCSI,
|
|
"convert_SCSI_device: node 0x%x Begin.....\n", node);
|
|
|
|
if (OFGetproplen(ph, "reg") > 0) {
|
|
regp = get_reg_prop(ph, "reg", 0);
|
|
node->Component.Key = regp->hi;
|
|
node->Child->Component.Key = 0;
|
|
--lock;
|
|
return (node);
|
|
}
|
|
|
|
debug(VRDBG_SCSI|VRDBG_TREE,
|
|
"convert_SCSI_device: wildcard node (0x%x) parent (0x%x)\n",
|
|
node, parent);
|
|
VRDBG(VRDBG_SCSI, vr_dump_config_node(node));
|
|
|
|
//
|
|
// Discard the existing node: it's a wildcard and does
|
|
// us no good.
|
|
//
|
|
debug(VRDBG_SCSI, "convert_SCSI_device: parent child is(0x%x)\n",
|
|
parent->Child);
|
|
if (parent->Child == node) {
|
|
parent->Child = node->Peer;
|
|
debug(VRDBG_SCSI, "convert_SCSI_device: reset parent->Child \n");
|
|
VRDBG(VRDBG_SCSI, vr_dump_config_node(parent->Child));
|
|
}
|
|
for (newnode = parent->Child; newnode; newnode = newnode->Peer) {
|
|
debug(VRDBG_SCSI, "convert_SCSI_device: new node (0x%x)\n",newnode);
|
|
if (newnode->Peer == node) {
|
|
newnode->Peer = node->Peer;
|
|
node->Peer = 0;
|
|
}
|
|
}
|
|
if (node->Child) {
|
|
free((char *) node->Child);
|
|
}
|
|
|
|
//
|
|
// and finally, free the node...
|
|
//
|
|
free((char *) node);
|
|
|
|
|
|
//
|
|
// Have we already done this SCSI bus?
|
|
//
|
|
for (i = 0; i < 32; ++i) {
|
|
if (done_list[i] == 0) {
|
|
break;
|
|
}
|
|
if (done_list[i] == parent) {
|
|
debug(VRDBG_SCSI|VRDBG_TREE,
|
|
"already did node (0x%x)\n", parent);
|
|
--lock;
|
|
return (0);
|
|
}
|
|
}
|
|
if (i >= 32) {
|
|
fatal("Too many (>32) SCSI adapters!\n");
|
|
}
|
|
done_list[i] = parent;
|
|
|
|
if (get_bool_prop(parentph, "wide")) {
|
|
debug(VRDBG_TREE|VRDBG_SCSI, "SCSI controller is wide \n");
|
|
|
|
max_scsi_target = 16;
|
|
|
|
tmp_scsi_host_id = get_int_prop(parentph, "scsi-initiator-id");
|
|
|
|
debug(VRDBG_SCSI, "SCSI_Initiator_Id = %x\n", tmp_scsi_host_id);
|
|
if ( (tmp_scsi_host_id >= 0) && (tmp_scsi_host_id < 16) ) {
|
|
scsi_host_id = tmp_scsi_host_id;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build the parent adapter's path.
|
|
//
|
|
path = NodeToPath(parent);
|
|
ih = OFOpen(path);
|
|
|
|
//
|
|
// Loop through possible targets, and record each one
|
|
// which responds.
|
|
//
|
|
for (i = 0; i < max_scsi_target; ++i) {
|
|
if (i == scsi_host_id) {
|
|
continue; // don't want to probe the scsi host!
|
|
}
|
|
|
|
//
|
|
// This algorithm uses methods that are standard
|
|
// in the scsi node, but are not explicitly exported
|
|
// through the client interface--thus the "call-method."
|
|
//
|
|
OFCallMethod(0, 4, 0, "set-address", ih, i, 0);
|
|
OFCallMethod(2, 5, res, "short-data-command", ih, 6, inq, 0xff);
|
|
if (res[0] != 0) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// The command succeeded.
|
|
//
|
|
inq_data = (UCHAR *) res[1];
|
|
if (inq_data[0] == 0x7f) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// What kind of device are we looking for?
|
|
//
|
|
debug(VRDBG_TREE|VRDBG_SCSI,
|
|
"convert_SCSI_device: Device Found @ id %d\n",i);
|
|
newtype = ScsiNodeType[inq_data[0]];
|
|
debug(VRDBG_TREE|VRDBG_SCSI,
|
|
"convert_SCSI_device:\t\t '%s' of Type '%s'\n",
|
|
ScsiNodeName[inq_data[0]], TypeNames[newtype]);
|
|
//
|
|
// This target is for real. Add a new node to represent
|
|
// this device. Touch up the node as necessary
|
|
// for proper key, identifier, etc.
|
|
//
|
|
newnode = add_new_child(parent, ScsiNodeName[inq_data[0]],
|
|
ControllerClass, newtype);
|
|
|
|
newnode->OfPhandle = ph;
|
|
newnode->Component.Key = i;
|
|
newnode->Component.Identifier = (char *)zalloc(29);
|
|
bcopy(&inq_data[8], newnode->Component.Identifier, 28);
|
|
newnode->Component.IdentifierLength = 29;
|
|
newnode->Wildcard = 1;
|
|
newnode->WildcardAddrPath = (char *) zalloc(6);
|
|
strcpy(newnode->WildcardAddrPath, "@X,0");
|
|
|
|
//
|
|
// Convert scsi id to hex string value...
|
|
//
|
|
if (i < 10) {
|
|
newnode->WildcardAddrPath[1] = '0' + i;
|
|
} else {
|
|
newnode->WildcardAddrPath[1] = 'a' + (i-10);
|
|
}
|
|
|
|
if (!convert_controller(newnode)) {
|
|
debug(VRDBG_TEST|VRDBG_SCSI|VRDBG_TREE,
|
|
"Convert_SCSI_device: failed convert_controller\n");
|
|
}
|
|
newnode->Child->Component.Key = 0;
|
|
newnode->Child->Wildcard = 1;
|
|
|
|
} // end of for loop probing scsi bus
|
|
OFClose(ih);
|
|
free(path);
|
|
--lock;
|
|
return (0); // Zero because this was a wildcard node; don't convert.
|
|
}
|
|
|
|
/*
|
|
* Like SCSI, devices may be wildcarded, so we've got to probe
|
|
* the whole bus here if we find a wildcard node.
|
|
*/
|
|
STATIC CONFIGURATION_NODE *
|
|
convert_IDE_device(PCONFIGURATION_NODE node)
|
|
{
|
|
PCONFIGURATION_NODE newnode, parent=node->Parent;
|
|
CONFIGURATION_TYPE type = node->Component.Type, newtype;
|
|
phandle ph = node->OfPhandle;
|
|
static PCONFIGURATION_NODE done_list[32] = { 0 };
|
|
reg *regp;
|
|
char *path;
|
|
int i;
|
|
ihandle ih;
|
|
ULONG res[3];
|
|
static int lock = 0;
|
|
|
|
if (lock++) {
|
|
--lock;
|
|
return(0);
|
|
}
|
|
debug(VRDBG_TREE, "convert_IDE_device: node 0x%x\n", node);
|
|
|
|
if (OFGetproplen(ph, "reg") > 0) {
|
|
regp = get_reg_prop(ph, "reg", 0);
|
|
node->Component.Key = regp->hi;
|
|
node->Child->Component.Key = 0;
|
|
--lock;
|
|
return (node);
|
|
}
|
|
|
|
debug(VRDBG_IDE, "convert_IDE_device: wildcard node (0x%x)\n", node);
|
|
VRDBG(VRDBG_IDE, vr_dump_config_node(node));
|
|
|
|
//
|
|
// Discard the existing node: it's a wildcard and does
|
|
// us no good.
|
|
//
|
|
|
|
debug(VRDBG_IDE, "convert_IDE_device: parent child is(0x%x)\n",
|
|
parent->Child);
|
|
if (parent->Child == node) {
|
|
//
|
|
// remove this node from the parent's lineage...
|
|
//
|
|
parent->Child = node->Peer;
|
|
debug(VRDBG_IDE, "convert_IDE_device: reset parent->Child \n");
|
|
VRDBG(VRDBG_IDE, vr_dump_config_node(parent->Child));
|
|
}
|
|
|
|
//
|
|
// Run the list of peers and see who points to this wild card node.
|
|
// Once the wildcard's sibling is located, remove the wildcard
|
|
// from the "peer" list.
|
|
//
|
|
for (newnode = parent->Child; newnode; newnode = newnode->Peer) {
|
|
debug(VRDBG_IDE, "convert_IDE_device: new node (0x%x)\n",newnode);
|
|
if (newnode->Peer == node) {
|
|
//
|
|
// Now, remove this node from its peer(s)'s line
|
|
// of siblings....
|
|
//
|
|
newnode->Peer = node->Peer;
|
|
debug(VRDBG_IDE, "convert_IDE_device: reset newnode->Peer \n");
|
|
VRDBG(VRDBG_IDE, vr_dump_config_node(newnode));
|
|
node->Peer = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// make sure this node's children are freed up since
|
|
// the children of a wild card node are wild themselves.
|
|
//
|
|
if (node->Child) {
|
|
debug(VRDBG_IDE, "convert_IDE_device: free child(0x%x)\n",
|
|
node->Child);
|
|
free((char *) node->Child);
|
|
}
|
|
|
|
//
|
|
// and finally, zero and free the node...
|
|
//
|
|
free((char *) node);
|
|
|
|
//
|
|
// Have we already done this IDE bus?
|
|
//
|
|
for (i = 0; i < 32; ++i) {
|
|
if (done_list[i] == 0) {
|
|
break;
|
|
}
|
|
if (done_list[i] == parent) {
|
|
debug(VRDBG_IDE|VRDBG_TREE,
|
|
"already did node (0x%x)\n", parent);
|
|
--lock;
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
if (i >= 32){
|
|
fatal("Too many (>32) IDE adapters!\n");
|
|
}
|
|
done_list[i] = parent;
|
|
|
|
//
|
|
// Build the parent adapter's path.
|
|
//
|
|
path = NodeToPath(parent);
|
|
ih = OFOpen(path);
|
|
//
|
|
// Loop through possible targets, and record each one
|
|
// which responds.
|
|
//
|
|
|
|
for (i = 0; i < MAX_IDE_DEVICE; ++i) {
|
|
//
|
|
// This algorithm uses methods that are standard
|
|
// in the ide package, but are not explicitly exported
|
|
// through the client interface--thus the "call-method."
|
|
//
|
|
|
|
OFCallMethod(3, 3, res, "ide-drive-inquiry", ih, i);
|
|
//
|
|
// The command succeeded.
|
|
//
|
|
|
|
if (res[0] == 0) {
|
|
continue;
|
|
}
|
|
|
|
debug(VRDBG_TREE, "convert_IDE_device: Device Found @ id %d\n",i);
|
|
newtype = ScsiNodeType[res[1]];
|
|
debug(VRDBG_TREE, "convert_IDE_device:\t\t '%s' of Type '%s'\n",
|
|
ScsiNodeName[res[1]], TypeNames[newtype]);
|
|
|
|
//
|
|
// What kind of device are we looking for?
|
|
//
|
|
newnode = add_new_child(parent, ScsiNodeName[res[1]],
|
|
ControllerClass, newtype);
|
|
newnode->OfPhandle = ph;
|
|
newnode->Component.Key = i;
|
|
newnode->Component.Identifier = "disk";
|
|
newnode->Component.IdentifierLength = 5;
|
|
newnode->Wildcard = 1;
|
|
newnode->WildcardAddrPath = (char *) zalloc(6);
|
|
strcpy(newnode->WildcardAddrPath, "@X,0");
|
|
newnode->WildcardAddrPath[1] = '0' + i;
|
|
|
|
if (!convert_controller(newnode)) {
|
|
debug(VRDBG_TEST,
|
|
"Convert_IDE_device: failed convert_controller\n");
|
|
}
|
|
newnode->Child->Component.Key = 0;
|
|
newnode->Child->Wildcard = 1;
|
|
|
|
}
|
|
OFClose(ih);
|
|
free(path);
|
|
--lock;
|
|
return (0); // Zero because this was a wildcard node; don't convert.
|
|
}
|
|
|
|
#define prl_t CM_PARTIAL_RESOURCE_LIST
|
|
#define prd_t CM_PARTIAL_RESOURCE_DESCRIPTOR
|
|
|
|
STATIC prl_t *
|
|
grow_prl(PCONFIGURATION_NODE node, int dev_specific)
|
|
{
|
|
prl_t *prl;
|
|
int datalen;
|
|
|
|
if (node->ConfigurationData == (prl_t *) 0) {
|
|
node->ConfigurationData =
|
|
(PCM_PARTIAL_RESOURCE_LIST)
|
|
zalloc(sizeof(CM_PARTIAL_RESOURCE_LIST) + dev_specific);
|
|
prl = node->ConfigurationData;
|
|
prl->Version = 1;
|
|
prl->Revision = 2;
|
|
prl->Count = 0;
|
|
node->Component.ConfigurationDataLength =
|
|
sizeof(CM_PARTIAL_RESOURCE_LIST) + dev_specific;
|
|
return (prl);
|
|
}
|
|
datalen = node->Component.ConfigurationDataLength +
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + dev_specific;
|
|
node->Component.ConfigurationDataLength = datalen;
|
|
prl = (prl_t *) zalloc(datalen);
|
|
datalen -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + dev_specific;
|
|
bcopy((char *) node->ConfigurationData, (char *) prl, datalen);
|
|
free((char *)node->ConfigurationData);
|
|
node->ConfigurationData = prl;
|
|
return(prl);
|
|
}
|
|
|
|
/*
|
|
* This extremely ad hoc routine is called when converting a floppy
|
|
* controller, and builds the appropriate device-specific data struct
|
|
* in the floppy peripheral (which is a child of the controller node).
|
|
*/
|
|
STATIC VOID
|
|
convert_config_floppy(CONFIGURATION_NODE *node)
|
|
{
|
|
PCM_FLOPPY_DEVICE_DATA fdd;
|
|
prl_t *prl;
|
|
prd_t *prd;
|
|
|
|
debug(VRDBG_TREE, "Convert_config_floppy: node 0x%x\n", *node);
|
|
node->ComponentName = "disk";
|
|
node->Component.Identifier = "I82077";
|
|
node->Component.IdentifierLength = 7;
|
|
|
|
node = node->Child;
|
|
//
|
|
// Add space for the floppy configuration data to the end of the
|
|
// configuration node:
|
|
//
|
|
prl = grow_prl(node, sizeof(CM_FLOPPY_DEVICE_DATA));
|
|
|
|
//
|
|
// set the partial resource descriptor pointer to the end of the
|
|
// configuration node before this new data area was added:
|
|
//
|
|
prd = &prl->PartialDescriptors[prl->Count];
|
|
|
|
//
|
|
// Tell the registry this data is device specific, and the resource
|
|
// is device exclusive. Basically, fill out a partial resource
|
|
// descriptor for the floppy:
|
|
//
|
|
prd->Type = CmResourceTypeDeviceSpecific;
|
|
prd->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
prd->Flags = 0;
|
|
prd->u.DeviceSpecificData.DataSize = sizeof(CM_FLOPPY_DEVICE_DATA);
|
|
|
|
//
|
|
// finally, increment the count to match the increase in the data
|
|
// added to the partial resource list
|
|
//
|
|
prl->Count += 1;
|
|
|
|
//
|
|
// Device-specific data begins immediately after
|
|
// its descriptor.
|
|
//
|
|
fdd = (PCM_FLOPPY_DEVICE_DATA)
|
|
((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
//
|
|
// These need to be version 1.2, else all the extended fields
|
|
// like "HeadSettleTime" are assumed to be valid and must be
|
|
// filled in, presumably by a scientist.
|
|
//
|
|
fdd->Version = 1;
|
|
fdd->Revision = 2;
|
|
strcpy(fdd->Size, "3.5");
|
|
fdd->MaxDensity = 1440;
|
|
/* All else is zero. */
|
|
}
|
|
|
|
/*
|
|
* This extremely ad hoc routine is called when converting a serial
|
|
* controller, and builds the appropriate device-specific data struct.
|
|
*/
|
|
STATIC VOID
|
|
convert_config_serial(CONFIGURATION_NODE *node)
|
|
{
|
|
PCM_SERIAL_DEVICE_DATA serd;
|
|
prl_t *prl;
|
|
prd_t *prd;
|
|
|
|
debug(VRDBG_TREE, "Convert_config_serial: node 0x%x\n", *node);
|
|
prl = grow_prl(node, sizeof(CM_SERIAL_DEVICE_DATA));
|
|
prd = &prl->PartialDescriptors[prl->Count];
|
|
prd->Type = CmResourceTypeDeviceSpecific;
|
|
prd->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
prd->Flags = 0;
|
|
prd->u.DeviceSpecificData.DataSize = sizeof(CM_SERIAL_DEVICE_DATA);
|
|
prl->Count += 1;
|
|
|
|
//
|
|
// Device-specific data begins immediately after
|
|
// its descriptor.
|
|
//
|
|
serd = (PCM_SERIAL_DEVICE_DATA)
|
|
((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
serd->Version = 1;
|
|
serd->Revision = 2;
|
|
if (VrDebug & SANDALFOOT) {
|
|
serd->BaudClock = 0x409980;
|
|
} else {
|
|
serd->BaudClock = 1843200;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This extremely ad hoc routine is called when converting the system
|
|
* node, and builds the appropriate device-specific data struct.
|
|
*/
|
|
STATIC VOID
|
|
convert_system_node(CONFIGURATION_NODE *node)
|
|
{
|
|
prl_t *prl;
|
|
prd_t *prd;
|
|
phandle ph;
|
|
PCHAR pData;
|
|
PCHAR pFirmwareVersion, pVeneerVersion;
|
|
PCHAR pVeneerVersionId = "Veneer";
|
|
PCHAR pFirmwareVersionId = "Firmware";
|
|
#ifdef BUILTBY
|
|
PCHAR pBuiltById = "Built By";
|
|
PCHAR pBuiltBy;
|
|
#endif
|
|
CHAR **srcPairs[] = {
|
|
&pFirmwareVersionId,
|
|
&pFirmwareVersion,
|
|
&pVeneerVersionId,
|
|
&pVeneerVersion,
|
|
#ifdef BUILTBY
|
|
&pBuiltById,
|
|
&pBuiltBy,
|
|
#endif
|
|
NULL
|
|
};
|
|
LONG dataSize;
|
|
LONG n;
|
|
|
|
debug(VRDBG_TREE, "Convert_system_node: node 0x%x\n", *node);
|
|
|
|
//
|
|
// The configuration data being built here will consist of
|
|
// multiple null terminated strings terminated by an empty
|
|
// string (ie. '\0'). The strings will consist of pairs
|
|
// of strings with the first string being the description
|
|
// of the second (paired) string.
|
|
//
|
|
// Example:
|
|
//
|
|
// "VeneerVersion" "FirmWorks,ENG,00.23,1995-04-27,14:42:21,GENERAL"
|
|
//
|
|
|
|
//
|
|
// grab the firmware and veneer versions
|
|
//
|
|
|
|
pVeneerVersion = VeneerVersion();
|
|
ph = OFFinddevice("/openprom");
|
|
pFirmwareVersion = get_str_prop(ph, "model", NOALLOC);
|
|
level_equals_vector = (OFGetproplen(ph,"arc-interrupt-level=vector") >= 0);
|
|
if (OFGetproplen(ph,"arc-interrupt-level") > 0) {
|
|
default_interrupt_level = get_int_prop(ph, "arc-interrupt-level");
|
|
}
|
|
if (OFGetproplen(ph,"arc-interrupt-affinity") > 0) {
|
|
default_interrupt_affinity = get_int_prop(ph, "arc-interrupt-affinity");
|
|
}
|
|
|
|
#ifdef BUILTBY
|
|
//
|
|
// add the built by if defined
|
|
//
|
|
pBuiltBy = IQUOTE(BUILTBY);
|
|
#endif
|
|
|
|
//
|
|
// the length of all strings + null terminaters + empty string
|
|
//
|
|
|
|
dataSize = 0;
|
|
for (n = 0; srcPairs[n]; n++) {
|
|
dataSize += strlen(*srcPairs[n]) + 1;
|
|
}
|
|
dataSize += 2*sizeof(CHAR); // an empty string (2* just for good measure)
|
|
|
|
prl = grow_prl(node, dataSize);
|
|
prd = &prl->PartialDescriptors[prl->Count];
|
|
prd->Type = CmResourceTypeDeviceSpecific;
|
|
prd->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
prd->Flags = 0;
|
|
prd->u.DeviceSpecificData.DataSize = dataSize;
|
|
prl->Count += 1;
|
|
debug(VRDBG_TEST, "Count is now...%x\n", prl->Count);
|
|
|
|
//
|
|
// Device-specific data begins immediately after
|
|
// its descriptor.
|
|
//
|
|
|
|
pData = (char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
|
|
{
|
|
//
|
|
// Now stuff the strings into the data buffer.
|
|
//
|
|
|
|
PCHAR dst = pData;
|
|
PCHAR src;
|
|
|
|
for (n = 0; srcPairs[n]; n++) {
|
|
src = *srcPairs[n];
|
|
strcpy(dst, src);
|
|
dst += strlen(src)+1;
|
|
}
|
|
|
|
*dst = '\0';
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// 8042 subtrees compliant with the HRP binding define a new address
|
|
// space for their children. Reg[0] in the child specifies the keyboard (0)
|
|
// or aux (1) port of the 8042. All 8042 child nodes--keyboard and
|
|
// mouse--are translated to ARC nodes--kbd and point--that have the same
|
|
// PORT information in the registry. The reg information in the device
|
|
// tree is suppressed, and the NT driver (i8042prt) sorts out who gets
|
|
// what port on the 8042.
|
|
// Although we shouldn't, we'll just "know" that an 8042 has two reg
|
|
//
|
|
STATIC VOID
|
|
convert_config_i8042(CONFIGURATION_NODE *node)
|
|
{
|
|
phandle parent;
|
|
prl_t *prl;
|
|
prd_t *prd;
|
|
int i;
|
|
reg *regp;
|
|
|
|
debug(VRDBG_TREE, "Convert_config_i8042: node 0x%x\n", *node);
|
|
parent = OFParent(node->OfPhandle);
|
|
for (i = 0; i < 2; ++i) {
|
|
regp = get_reg_prop(parent, "reg", i);
|
|
prl = grow_prl(node, 0);
|
|
prd = &prl->PartialDescriptors[prl->Count];
|
|
prd->Type = CmResourceTypePort;
|
|
prd->Flags = CM_RESOURCE_PORT_IO;
|
|
prd->u.Port.Start.LowPart = regp->lo;
|
|
prd->u.Port.Start.HighPart = 0;
|
|
prd->u.Port.Length = regp->size;
|
|
prd->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
prl->Count += 1;
|
|
}
|
|
}
|
|
|
|
STATIC VOID
|
|
replace_isa_name(CONFIGURATION_NODE *node, int port)
|
|
{
|
|
struct pnp_info *pnp;
|
|
|
|
for (pnp = pnp_data; pnp->port != 0; ++pnp) {
|
|
if (pnp->port == (unsigned int) port) {
|
|
node->Component.Identifier = pnp->id;
|
|
node->Component.IdentifierLength = strlen(pnp->id) + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC VOID
|
|
convert_config(CONFIGURATION_NODE *node)
|
|
{
|
|
phandle ph = node->OfPhandle;
|
|
prl_t *prl;
|
|
prd_t *prd=0;
|
|
reg *regp;
|
|
int prop;
|
|
|
|
debug(VRDBG_TREE, "convert_config: node 0x%x, name %s identifier %s\n",
|
|
node, node->ComponentName, node->Component.Identifier);
|
|
//
|
|
// The "arc-config-data" property totally overrides the conversion
|
|
// process, providing a complete verbatim ARC configuration data
|
|
// structure.
|
|
//
|
|
if ((prop = OFGetproplen(ph, "arc-config-data")) >= 0) {
|
|
char *buf;
|
|
debug(VRDBG_ARCDATA, "convert_config: arc data override: 0x%x\n", node);
|
|
buf = zalloc(prop);
|
|
(VOID) OFGetprop(ph, "arc-config-data", buf, prop);
|
|
node->ConfigurationData = (PCM_PARTIAL_RESOURCE_LIST) buf;
|
|
node->Component.ConfigurationDataLength = prop;
|
|
|
|
if (((prop = OFGetproplen(ph, "reg")) > 0)
|
|
&& (strcmp(node->Parent->Component.Identifier, "ISA") == 0)) {
|
|
regp = get_reg_prop(ph, "reg", 0);
|
|
replace_isa_name(node, regp->lo);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ((prop = OFGetproplen(ph, "reg")) > 0) {
|
|
if (strcmp(node->ComponentName, "memory") == 0) {
|
|
regp = get_reg_prop(ph, "reg", 0);
|
|
ADD_MEM_RESOURCE(regp, node);
|
|
} else {
|
|
if (strcmp(node->Parent->Component.Identifier, "PCI") == 0) {
|
|
regp = get_reg_prop(ph, "reg", 1);
|
|
configure_pci_node(regp, node);
|
|
} else {
|
|
if (strcmp(node->Component.Identifier, "I8042PRT") == 0) {
|
|
convert_config_i8042(node);
|
|
} else {
|
|
regp = get_reg_prop(ph, "reg", 0);
|
|
ADD_IO_RESOURCE(regp, node);
|
|
replace_isa_name(node, prd->u.Port.Start.LowPart);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((prop = OFGetproplen(ph, "interrupts")) > 0) {
|
|
int level;
|
|
level = get_int_prop(ph, "interrupts");
|
|
ADD_INT_RESOURCE(level, node);
|
|
//
|
|
// Now check for deviations from the "NORM" in the form of
|
|
// arc-... properties that this particular system uses to
|
|
// override standard tree values.
|
|
//
|
|
if ((prop = OFGetproplen(ph, "arc-interrupt-flags")) > 0) {
|
|
prop = get_int_prop(ph, "arc-interrupt-flags");
|
|
prd->Flags = prop;
|
|
}
|
|
if ((prop = OFGetproplen(ph, "arc-interrupt-level")) > 0) {
|
|
prop = get_int_prop(ph, "arc-interrupt-level");
|
|
prd->u.Interrupt.Level = prop;
|
|
}
|
|
|
|
if ((prop = OFGetproplen(ph, "arc-interrupt-vector")) > 0) {
|
|
prop = get_int_prop(ph, "arc-interrupt-vector");
|
|
prd->u.Interrupt.Vector = prop;
|
|
}
|
|
|
|
if ((prop = OFGetproplen(ph, "arc-interrupt-affinity")) > 0) {
|
|
(int)(prd->u.Interrupt.Affinity) =
|
|
get_int_prop(ph, "arc-interrupt-affinity");
|
|
}
|
|
|
|
}
|
|
|
|
if ((prop = OFGetproplen(ph, "dma")) > 0) {
|
|
prop = get_int_prop(ph, "dma");
|
|
ADD_DMA_RESOURCE(prop, node);
|
|
if (prop != sizeof(int)) {
|
|
//
|
|
// Multiple cells are used to encode PNP data for
|
|
// AIX--just pick off the first cell.
|
|
//
|
|
char buf[sizeof(int)];
|
|
OFGetprop(ph, "dma", buf, sizeof(int));
|
|
prop = decode_int(buf);
|
|
prd->u.Dma.Channel = prop;
|
|
}
|
|
}
|
|
|
|
if ((prop = OFGetproplen(ph, "arc-device-specific")) > 0) {
|
|
ADD_DEVICE_SPECIFIC_RESOURCE(prop, node);
|
|
}
|
|
|
|
//
|
|
// Now check for special-case conversions.
|
|
//
|
|
|
|
debug(VRDBG_TREE, "\tCheck special case, Name '%s'\n",
|
|
node->ComponentName);
|
|
|
|
if (strcmp(node->ComponentName, "floppy") == 0) {
|
|
convert_config_floppy(node);
|
|
}
|
|
|
|
if (strcmp(node->ComponentName, "serial") == 0) {
|
|
convert_config_serial(node);
|
|
}
|
|
|
|
#ifdef SANDALFOOT_YET_LIVES
|
|
//
|
|
// Empirically, Sandalfoot systems have this stuff (register
|
|
// init constants?) in their ARC trees. Ergo, we put it
|
|
// in our ARC trees too. Note that this stuff doesn't look
|
|
// like a normal node.
|
|
//
|
|
if (strcmp(node->ComponentName, "video") == 0) {
|
|
PULONG up;
|
|
|
|
node = node->Child;
|
|
prl = grow_prl(node, 0x1a);
|
|
prl->Version = 1;
|
|
prl->Revision = 0;
|
|
|
|
up = (PULONG) &prl->Count;
|
|
*up++ = 0x3e800400;
|
|
*up++ = 0x03e807d0;
|
|
*up++ = 0x030005dc;
|
|
*up++ = 0x00010027;
|
|
*up++ = 0x01570001;
|
|
*up++ = 0x00000112;
|
|
|
|
}
|
|
#endif
|
|
|
|
if (node->Component.Type == ArcSystem) {
|
|
convert_system_node(node);
|
|
}
|
|
}
|
|
|
|
STATIC VOID
|
|
convert_cache(CONFIGURATION_NODE *node)
|
|
{
|
|
phandle ph = node->OfPhandle;
|
|
CONFIGURATION_NODE *newnode;
|
|
int block_size, cache_size;
|
|
|
|
debug(VRDBG_TREE, "Convert_cache: node 0x%x\n", node);
|
|
if (get_bool_prop(ph, "cache-unified")) {
|
|
cache_size = get_int_prop(ph, "i-cache-size");
|
|
if (cache_size == -1) {
|
|
fatal("Couldn't find 'i-cache-size': %s\n", node->ComponentName);
|
|
}
|
|
block_size = get_int_prop(ph, "i-cache-block-size");
|
|
if (block_size == -1) {
|
|
block_size = 8;
|
|
}
|
|
|
|
node->Component.Key = 0x01000000;
|
|
node->Component.Key |= log2(block_size) << 16;
|
|
node->Component.Key |= log2(cache_size >> PAGE_SHIFT);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Are we an I-cache?
|
|
//
|
|
if (get_int_prop(ph, "i-cache-size") != -1) {
|
|
cache_size = get_int_prop(ph, "i-cache-size");
|
|
block_size = get_int_prop(ph, "i-cache-block-size");
|
|
if (block_size == -1) {
|
|
fatal("Couldn't find 'i-cache-block-size': %s\n",
|
|
node->ComponentName);
|
|
}
|
|
|
|
node->Component.Key = 0x01000000;
|
|
node->Component.Key |= log2(block_size) << 16;
|
|
node->Component.Key |= log2(cache_size >> PAGE_SHIFT);
|
|
|
|
if (node->Parent->Component.Type == CentralProcessor) {
|
|
node->Component.Type = PrimaryIcache;
|
|
} else {
|
|
node->Component.Type = SecondaryIcache;
|
|
}
|
|
|
|
if (get_int_prop(ph, "d-cache-size") == -1) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Uh-oh, there's a split cache here.
|
|
//
|
|
newnode = new(CONFIGURATION_NODE);
|
|
bcopy((char *) node, (char *) newnode, sizeof(CONFIGURATION_NODE));
|
|
newnode->Child = 0;
|
|
node->Peer = newnode;
|
|
node = newnode;
|
|
}
|
|
|
|
//
|
|
// Are we a D-cache?
|
|
//
|
|
if (get_int_prop(ph, "d-cache-size") != -1) {
|
|
cache_size = get_int_prop(ph, "d-cache-size");
|
|
block_size = get_int_prop(ph, "d-cache-block-size");
|
|
if (block_size == -1) {
|
|
fatal("Couldn't find 'd-cache-block-size': %s\n",
|
|
node->ComponentName);
|
|
}
|
|
|
|
node->Component.Key = 0x01000000;
|
|
node->Component.Key |= log2(block_size) << 16;
|
|
node->Component.Key |= log2(cache_size >> PAGE_SHIFT);
|
|
|
|
if (node->Parent->Component.Type == CentralProcessor) {
|
|
node->Component.Type = PrimaryDcache;
|
|
} else {
|
|
node->Component.Type = SecondaryDcache;
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC VOID
|
|
update_display_node(PCONFIGURATION_NODE node)
|
|
{
|
|
PCONFIGURATION_NODE n;
|
|
|
|
if (DisplayNode == 0) {
|
|
DisplayNode = node;
|
|
return;
|
|
}
|
|
|
|
if (DisplayNode->Child) {
|
|
free((char *) DisplayNode->Child);
|
|
}
|
|
|
|
n = DisplayNode->Parent;
|
|
if (n->Child == DisplayNode) {
|
|
n->Child = DisplayNode->Peer;
|
|
} else {
|
|
for (n = n->Child; n && n->Peer != DisplayNode; n = n->Peer) {
|
|
;
|
|
}
|
|
if (n) {
|
|
n->Peer = DisplayNode->Peer;
|
|
}
|
|
}
|
|
|
|
free((char *) DisplayNode);
|
|
DisplayNode = node;
|
|
}
|
|
|
|
STATIC VOID
|
|
configure_pci_node(reg *regp, PCONFIGURATION_NODE node)
|
|
{
|
|
prl_t *prl;
|
|
prd_t *prd;
|
|
debug(VRDBG_TREE, "Convert_pci_node: node 0x%x\n", node);
|
|
if (regp != NULL) {
|
|
prl = grow_prl(node, 0);
|
|
prd = &prl->PartialDescriptors[prl->Count];
|
|
prd->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
|
|
switch (regp->hi & 0x0f000000) {
|
|
case 0x01000000:
|
|
prd->Type = CmResourceTypePort;
|
|
prd->Flags = CM_RESOURCE_PORT_IO;
|
|
prd->u.Port.Start.LowPart = regp->lo;
|
|
prd->u.Port.Start.HighPart = 0;
|
|
break;
|
|
case 0x02000000:
|
|
case 0x03000000:
|
|
//
|
|
// XXX this is really quite bogus - we should probably
|
|
// look in the assigned-addresses property to find
|
|
// the actual assigned base address. However, we
|
|
// don't really know yet exactly what this property is
|
|
// supposed to contain for PCI devices.
|
|
//
|
|
|
|
prd->Type = CmResourceTypeMemory;
|
|
prd->Flags = 0;
|
|
prd->u.Memory.Start.LowPart = regp->lo;
|
|
prd->u.Memory.Start.HighPart = 0;
|
|
// XXX do something for 64-bit memory space
|
|
break;
|
|
}
|
|
prd->u.Port.Length = regp->size;
|
|
prl->Count += 1;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Routine: vr_dump_config_node(PCONFIGURATION_NODE)
|
|
*
|
|
* Description:
|
|
* To dump the open firmware info for the given node.
|
|
*/
|
|
|
|
VOID
|
|
vr_dump_config_node(PCONFIGURATION_NODE node)
|
|
{
|
|
CONFIGURATION_CLASS class;
|
|
CONFIGURATION_TYPE type;
|
|
PCHAR name="XXX";
|
|
|
|
if (!node) {
|
|
warn("vr_dump_config_node: NODE is invalid: 0x%x\n",node);
|
|
return;
|
|
}
|
|
class = node->Component.Class;
|
|
type = node->Component.Type;
|
|
|
|
if (class > MaximumClass ) {
|
|
warn("vr_dump_config: class value maxed out: previously 0x%x\n",class);
|
|
class = MaximumClass;
|
|
}
|
|
|
|
if (type > MaximumType) {
|
|
warn("vr_dump_config: type value maxed out: previously 0x%x\n",type);
|
|
type = MaximumType;
|
|
}
|
|
|
|
//
|
|
// Dump information to identify this node.
|
|
//
|
|
warn("\ndump_node:\tName\t%s\n", node->ComponentName);
|
|
warn("\t\tClass\t%s\t\t\tParent 0x%x\n",
|
|
ClassNames[class], node->Parent);
|
|
warn("\t\tType\t%s\t\t\t /\n", TypeNames[type]);
|
|
warn("\t\tKey\t%d\t\t\t Current 0x%x ----> Peer 0x%x\n",
|
|
node->Component.Key, node, node->Peer);
|
|
warn("\t\t\t\t\t\t/\n");
|
|
warn("\t\t\t\t\tChild 0x%x\n\n",node->Child);
|
|
|
|
}
|