/*
* 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);
}