blob: 56ed891e8cd53dbc9b05f31b72a248f8c9542bee [file] [log] [blame]
/**
* @file
*
* Coherent Discovery Routines.
*
* Contains routines for discovery, along with Temporary routing.
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: HyperTransport
* @e \$Revision: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
*
*/
/*
*****************************************************************************
*
* Copyright (c) 2011, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Advanced Micro Devices, Inc. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***************************************************************************
*
*/
/*
*----------------------------------------------------------------------------
* MODULES USED
*
*----------------------------------------------------------------------------
*/
#include "AGESA.h"
#include "Ids.h"
#include "Topology.h"
#include "htFeat.h"
#include "htInterface.h"
#include "htNotify.h"
#include "htNb.h"
#include "htFeatDynamicDiscovery.h"
#include "Filecode.h"
#define FILECODE PROC_HT_FEATURES_HTFEATDYNAMICDISCOVERY_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
#define LOGICAL_PROCESSOR_NONE 0xFF
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/**
* Status result from exploring for a new node on a link.
*/
typedef enum {
ExploreNodeStatusNew, ///< A new node was discovered
ExploreNodeStatusGood, ///< A new link to an already known node was discovered
ExploreNodeStatusStop, ///< Discovery must halt now.
ExploreNodeStatusIgnore, ///< A new node was ignored on purpose.
ExploreNodeStatusMax ///< Use for bounds check and limit only
} EXPLORE_NODE_STATUS;
/**
* Save all the information needed about a node at its discovery.
*
* When we can access the node at a known temporary route, read everything needed
* to do node to socket mapping, post to ap mailbox at later times.
*/
typedef struct {
UINT8 LogicalProcessor; ///< Independent of Node,Socket group nodes into logical
///< processors based on discovery.
UINT8 CurrentNode; ///< The node from which discovery occurred.
UINT8 CurrentLink; ///< The link on that node which we explored.
UINT8 PackageLink; ///< The package level link corresponding to CurrentLink.
UINT8 CurrentModuleType; ///< The current node's module type, Single or Multiple.
UINT8 CurrentModule; ///< This current node's module id.
UINT8 HardwareSocket; ///< Save the hardware socket strap (for hardware socket method).
UINT8 NewModuleType; ///< The new node's module type, Single or Multiple.
UINT8 NewModule; ///< The new node's module id.
} NEW_NODE_SAVED_INFO_ITEM;
/**
* A "no info" initializer for saved new node info.
*/
STATIC CONST NEW_NODE_SAVED_INFO_ITEM ROMDATA NoInfoSavedYet =
{
LOGICAL_PROCESSOR_NONE, 0, 0, 0, 0, 0, 0, 0
};
/**
* A list of all the new node info, indexed by each new node's nodeid.
*/
typedef NEW_NODE_SAVED_INFO_ITEM (*NEW_NODE_SAVED_INFO_LIST) [MAX_NODES];
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* EXPORTED FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/***************************************************************************
*** GENERIC HYPERTRANSPORT DISCOVERY CODE ***
***************************************************************************/
/*-----------------------------------------------------------------------------------*/
/**
* Ensure a request / response route from target Node to bsp.
*
* Since target Node is always a predecessor of actual target Node, each Node gets a
* route to actual target on the Link that goes to target. The routing produced by
* this routine is adequate for config access during discovery, but NOT for coherency.
*
* @param[in] TargetNode the path to actual target goes through target
* @param[in] ActualTarget the ultimate target being routed to
* @param[in] State our global state, port config info
*
*/
VOID
STATIC
routeFromBSP (
IN UINT8 TargetNode,
IN UINT8 ActualTarget,
IN STATE_DATA *State
)
{
UINT8 PredecessorNode;
UINT8 PredecessorLink;
UINT8 CurrentPair;
if (TargetNode == 0) {
return; // BSP has no predecessor, stop
}
// Search for the Link that connects TargetNode to its predecessor
CurrentPair = 0;
while ((*State->PortList)[CurrentPair*2 + 1].NodeID != TargetNode) {
CurrentPair++;
ASSERT (CurrentPair < State->TotalLinks);
}
PredecessorNode = (*State->PortList)[ (CurrentPair * 2)].NodeID;
PredecessorLink = (*State->PortList)[ (CurrentPair * 2)].Link;
// Recursively call self to ensure the route from the BSP to the Predecessor
// Node is established
routeFromBSP (PredecessorNode, ActualTarget, State);
State->Nb->WriteRoutingTable (PredecessorNode, ActualTarget, PredecessorLink, State->Nb);
}
/*----------------------------------------------------------------------------------------*/
/**
* Test Compatibility of a new node, and handle failure.
*
* Make the compatibility test call for the northbridge.
* If the new node is incompatible, force 1P. Notify the event.
* Additionally, invoke the northbridge stop link method, to
* implement isolation of the BSP from any incompatible node.
*
* @param[in] CurrentNode The node we are exploring from
* @param[in] CurrentLink The Link on that node to explore.
* @param[in] State Access to Northbridge interface.
*
* @retval TRUE Check is Ok
* @retval FALSE Check failed and is handled
*/
BOOLEAN
STATIC
CheckCompatible (
IN UINT8 CurrentNode,
IN UINT8 CurrentLink,
IN STATE_DATA *State
)
{
UINT8 NodeToKill;
BOOLEAN Result;
Result = TRUE;
// Check the northbridge of the Node we just found, to make sure it is compatible
// before doing anything else to it.
//
if (State->Nb->IsIllegalTypeMix ((CurrentNode + 1), State->Nb)) {
IDS_ERROR_TRAP;
// Notify BIOS of event
NotifyFatalCohProcessorTypeMix (
CurrentNode,
CurrentLink,
State->NodesDiscovered,
State
);
// If Node is not compatible, force boot to 1P
// If they are not compatible stop cHT init and:
// 1. Disable all cHT Links on the BSP
// 2. Configure the BSP routing tables as a UP.
// 3. Notify main BIOS.
//
State->NodesDiscovered = 0;
State->TotalLinks = 0;
// Abandon our coherent Link data structure. At this point there may
// be coherent Links on the BSP that are not yet in the portList, and
// we have to turn them off anyway. So depend on the hardware to tell us.
//
for (CurrentLink = 0; CurrentLink < State->Nb->MaxLinks; CurrentLink++) {
// Stop all Links which are connected, coherent, and ready
if (State->Nb->VerifyLinkIsCoherent (0, CurrentLink, State->Nb)) {
State->Nb->StopLink (0, CurrentLink, State, State->Nb);
}
}
for (NodeToKill = 0; NodeToKill < MAX_NODES; NodeToKill++) {
State->Nb->WriteFullRoutingTable (0, NodeToKill, ROUTE_TO_SELF, ROUTE_TO_SELF, 0, State->Nb);
}
State->HtInterface->CleanMapsAfterError (State);
// End Coherent Discovery
Result = FALSE;
}
return Result;
}
/*----------------------------------------------------------------------------------------*/
/**
* Check the system MP capability with a new node and handle any failure.
*
* Invoke the northbridge MP capability check. If it fails, notify the event and force
* 1P. Should not need to stop links on the BSP.
*
* @param[in] CurrentNode The node we are exploring from
* @param[in] CurrentLink The Link on that node to explore.
* @param[in] State Access to Northbridge interface.
*
* @retval TRUE Check is Ok
* @retval FALSE Check Failed and is handled
*/
BOOLEAN
STATIC
CheckCapable (
IN UINT8 CurrentNode,
IN UINT8 CurrentLink,
IN STATE_DATA *State
)
{
UINT8 NodeToKill;
BOOLEAN Result;
Result = TRUE;
// Check the capability of northbridges against the currently known configuration
if (State->Nb->IsExceededCapable ((CurrentNode + 1), State, State->Nb)) {
IDS_ERROR_TRAP;
// Notify BIOS of event
NotifyFatalCohMpCapMismatch (
CurrentNode,
CurrentLink,
State->SysMpCap,
State->NodesDiscovered,
State
);
State->NodesDiscovered = 0;
State->TotalLinks = 0;
for (NodeToKill = 0; NodeToKill < MAX_NODES; NodeToKill++) {
State->Nb->WriteFullRoutingTable (0, NodeToKill, ROUTE_TO_SELF, ROUTE_TO_SELF, 0, State->Nb);
}
State->HtInterface->CleanMapsAfterError (State);
// End Coherent Discovery
Result = FALSE;
}
return Result;
}
/*----------------------------------------------------------------------------------------*/
/**
* Make all the tests needed to determine if a link should be added to the system data structure.
*
* The link should be added to the system data structure if it is:
* - not being Ignored on this boot
* - not having a hard failure
* - coherent and connected
* - not already in the system data structure
* - not subject to some special handling case.
* .
*
* @param[in] CurrentNode The node we are exploring from
* @param[in] CurrentLink The Link on that node to explore.
* @param[in] State Access to Northbridge interface.
*
* @retval FALSE This link should not be added.
* @retval TRUE This link should explored and added to the system.
*/
BOOLEAN
STATIC
IsLinkToAdd (
IN UINT8 CurrentNode,
IN UINT8 CurrentLink,
IN STATE_DATA *State
)
{
BOOLEAN Linkfound;
UINTN Port;
FINAL_LINK_STATE FinalLinkState;
BOOLEAN Result;
Result = FALSE;
FinalLinkState = State->HtInterface->GetIgnoreLink (CurrentNode, CurrentLink, State->Nb->DefaultIgnoreLinkList, State);
if ((FinalLinkState != MATCHED) && (FinalLinkState != POWERED_OFF)) {
if (!State->Nb->ReadTrueLinkFailStatus (CurrentNode, CurrentLink, State, State->Nb)) {
// Make sure that the Link is connected, coherent, and ready
if (State->Nb->VerifyLinkIsCoherent (CurrentNode, CurrentLink, State->Nb)) {
// Test to see if the CurrentLink has already been explored
Linkfound = FALSE;
for (Port = 0; Port < State->TotalLinks; Port++) {
if ((((*State->PortList)[ (Port * 2 + 1)].NodeID == CurrentNode) &&
((*State->PortList)[ (Port * 2 + 1)].Link == CurrentLink)) ||
(((*State->PortList)[ (Port * 2)].NodeID == CurrentNode) &&
((*State->PortList)[ (Port * 2)].Link == CurrentLink))) {
Linkfound = TRUE;
break;
}
}
if (!Linkfound) {
if (!State->Nb->HandleSpecialLinkCase (CurrentNode, CurrentLink, State, State->Nb)) {
Result = TRUE;
}
}
}
}
} else {
if (FinalLinkState == POWERED_OFF) {
State->Nb->StopLink (CurrentNode, CurrentLink, State, State->Nb);
}
}
return Result;
}
/*----------------------------------------------------------------------------------------*/
/**
* Explore for a new node over a link, handling whatever is found.
*
* Open a temporary route over a link on the current node.
* Make checks for compatibility and capability in the proper sequence.
* If the node found is new, set a token to it, so it will be recognized in the
* future, and notify an event for finding a new node.
* If the node is already found (token is set), just return status.
*
* @param[in] CurrentNode The node we are exploring from
* @param[in] CurrentLink The Link on that node to explore.
* @param[in] LogicalProcessor The processor to update in the maps.
* @param[in,out] NewNodeSavedInfo The saved info for nodes in that processor.
* @param[in] State Access to Northbridge interface.
*
* @retval ExploreNodeStatusNew A new node was found
* @retval ExploreNodeStatusGood This is a good link to an already known node
* @retval ExploreNodeStatusStop Stop Coherent Discovery
*/
EXPLORE_NODE_STATUS
STATIC
ExploreNode (
IN UINT8 CurrentNode,
IN UINT8 CurrentLink,
IN UINT8 LogicalProcessor,
IN OUT NEW_NODE_SAVED_INFO_LIST NewNodeSavedInfo,
IN STATE_DATA *State
)
{
UINT8 Token;
EXPLORE_NODE_STATUS Status;
// Modify CurrentNode's routing table to use CurrentLink to send
// traffic to CurrentNode + 1
//
State->Nb->WriteRoutingTable (CurrentNode, (CurrentNode + 1), CurrentLink, State->Nb);
if (!State->Nb->HandleSpecialNodeCase ((CurrentNode + 1), CurrentLink, State, State->Nb)) {
if (CheckCompatible (CurrentNode, CurrentLink, State)) {
// Read Token from Current + 1
Token = State->Nb->ReadToken ((CurrentNode + 1), State->Nb);
ASSERT (Token <= State->NodesDiscovered);
if (Token == 0) {
State->NodesDiscovered++;
ASSERT (State->NodesDiscovered < MAX_NODES);
if (CheckCapable (CurrentNode, CurrentLink, State)) {
Token = State->NodesDiscovered;
State->Nb->WriteToken ((CurrentNode + 1), Token, State->Nb);
// Fill in Saved New Node info for the discovered node.
// We do this so we don't have to keep a temporary route open to it.
// So we save everything that might be needed to set the socket and node
// maps for either the software or hardware method.
//
(*NewNodeSavedInfo)[Token].LogicalProcessor = LogicalProcessor;
(*NewNodeSavedInfo)[Token].CurrentNode = CurrentNode;
(*NewNodeSavedInfo)[Token].CurrentLink = CurrentLink;
(*NewNodeSavedInfo)[Token].PackageLink = State->Nb->GetPackageLink (CurrentNode, CurrentLink, State->Nb);
(*NewNodeSavedInfo)[Token].HardwareSocket = State->Nb->GetSocket (Token, (CurrentNode + 1), State->Nb);
State->Nb->GetModuleInfo (
CurrentNode,
&((*NewNodeSavedInfo)[Token].CurrentModuleType),
&((*NewNodeSavedInfo)[Token].CurrentModule),
State->Nb
);
State->Nb->GetModuleInfo (
(CurrentNode + 1),
&((*NewNodeSavedInfo)[Token].NewModuleType),
&((*NewNodeSavedInfo)[Token].NewModule),
State->Nb
);
// Notify BIOS with info
NotifyInfoCohNodeDiscovered (
CurrentNode,
CurrentLink,
Token,
(CurrentNode + 1),
State
);
Status = ExploreNodeStatusNew;
} else {
// Failed Capable
Status = ExploreNodeStatusStop;
}
} else {
// Not a new node, token already set
Status = ExploreNodeStatusGood;
}
} else {
// Failed Compatible
Status = ExploreNodeStatusStop;
}
} else {
// Ignore this node
Status = ExploreNodeStatusIgnore;
}
return Status;
}
/*----------------------------------------------------------------------------------------*/
/**
* Process all the saved new node info for the current processor.
*
* When all nodes in the processor have been discovered, we can process all the saved
* info about the nodes. We add each node to the socket and node maps.
*
* @param[in] LogicalProcessor The processor to update in the maps.
* @param[in] NewNodeSavedInfo The saved info for nodes in that processor.
* @param[in] State Our system representation.
*/
VOID
STATIC
ProcessSavedNodeInfo (
IN UINT8 LogicalProcessor,
IN NEW_NODE_SAVED_INFO_LIST NewNodeSavedInfo,
IN STATE_DATA *State
)
{
UINT8 NewNode;
UINT8 HardwareSocket;
// Can't have more processors than nodes, just more (or equal) nodes than processors.
ASSERT (LogicalProcessor <= (State->NodesDiscovered));
HardwareSocket = 0xFF;
// Find the Hardware Socket value to use (if we are using the hardware socket naming method).
// The new nodes are the ones in this processor, so find the one that is module 0.
for (NewNode = 0; NewNode < (State->NodesDiscovered + 1); NewNode++) {
if (((*NewNodeSavedInfo)[NewNode].LogicalProcessor == LogicalProcessor) &&
((*NewNodeSavedInfo)[NewNode].NewModule == 0)) {
HardwareSocket = (*NewNodeSavedInfo)[NewNode].HardwareSocket;
break;
}
}
// We must have found a result, however, the hardware socket value doesn't have to be correct
// unless we are using the hardware socket naming method. Northbridge code should return the
// node number for the hardware socket if hardware socket strapping is not supported (i.e. no sbi).
ASSERT (HardwareSocket != 0xFF);
// Set the node to socket maps for this processor. Node zero is always handled specially,
// so skip it in this loop.
for (NewNode = 1; NewNode < (State->NodesDiscovered + 1); NewNode++) {
if ((*NewNodeSavedInfo)[NewNode].LogicalProcessor == LogicalProcessor) {
// For the currently discovered logical processor, update node to socket
// map for all the processor's nodes.
State->HtInterface->SetNodeToSocketMap (
(*NewNodeSavedInfo)[NewNode].CurrentNode,
(*NewNodeSavedInfo)[NewNode].CurrentModule,
(*NewNodeSavedInfo)[NewNode].PackageLink,
NewNode,
HardwareSocket,
(*NewNodeSavedInfo)[NewNode].NewModule,
State);
}
}
}
/*----------------------------------------------------------------------------------------*/
/**
* Create and add a new link to the system data structure.
*
* Add the two port list data structures, source first, initializing
* the two node ids and the link values. The node id of the remote
* node is its token value. Also, update the adjacency matrix and
* node degree table.
*
* @param[in] CurrentNode The node we are exploring from
* @param[in] CurrentLink The Link on that node to explore.
* @param[in] TempRoute The temporary node route that goes over that link.
* @param[in] State Access to Northbridge interface.
*
*/
VOID
STATIC
AddLinkToSystem (
IN UINT8 CurrentNode,
IN UINT8 CurrentLink,
IN UINT8 TempRoute,
IN STATE_DATA *State
)
{
UINT8 Token;
ASSERT (State->TotalLinks < MAX_PLATFORM_LINKS);
Token = State->Nb->ReadToken (TempRoute, State->Nb);
(*State->PortList)[State->TotalLinks * 2].Type = PORTLIST_TYPE_CPU;
(*State->PortList)[State->TotalLinks * 2].Link = CurrentLink;
(*State->PortList)[State->TotalLinks * 2].NodeID = CurrentNode;
(*State->PortList)[State->TotalLinks * 2 + 1].Type = PORTLIST_TYPE_CPU;
(*State->PortList)[State->TotalLinks * 2 + 1].Link = State->Nb->ReadDefaultLink (TempRoute, State->Nb);
(*State->PortList)[State->TotalLinks * 2 + 1].NodeID = Token;
State->TotalLinks++;
if ( !State->Fabric->SysMatrix[CurrentNode][Token] ) {
State->Fabric->SysDegree[CurrentNode]++;
State->Fabric->SysDegree[Token]++;
State->Fabric->SysMatrix[CurrentNode][Token] = TRUE;
State->Fabric->SysMatrix[Token][CurrentNode] = TRUE;
}
}
/*----------------------------------------------------------------------------------------*/
/**
* Start discovery from a new node.
*
* If the node is not the BSP, establish a route between the node and the
* BSP for request/response.
* Set the node id, and enable routing on this node. This gives us control
* on that node to isolate links, by specifying each link in turn as the route
* to a possible new node.
*
* @param[in] CurrentNode The node we are exploring from
* @param[in] State Access to Northbridge interface.
*
*/
VOID
STATIC
StartFromANewNode (
IN UINT8 CurrentNode,
IN STATE_DATA *State
)
{
if (CurrentNode != 0) {
// Set path from BSP to CurrentNode
routeFromBSP (CurrentNode, CurrentNode, State);
// Set path from BSP to CurrentNode for CurrentNode + 1 if
// CurrentNode + 1 != MAX_NODES
//
if ((CurrentNode + 1) != MAX_NODES) {
routeFromBSP (CurrentNode, (CurrentNode + 1), State);
}
// Configure CurrentNode to route traffic to the BSP through its
// default Link
//
State->Nb->WriteRoutingTable (CurrentNode, 0, State->Nb->ReadDefaultLink (CurrentNode, State->Nb), State->Nb);
}
// Set CurrentNode's NodeID field to CurrentNode
State->Nb->WriteNodeID (CurrentNode, CurrentNode, State->Nb);
// Enable routing tables on CurrentNode
State->Nb->EnableRoutingTables (CurrentNode, State->Nb);
}
/*----------------------------------------------------------------------------------------*/
/**
* Back up from exploring a one-deep internal node.
*
* When a newly discovered node has internal package links to another
* node in the same processor, discovery moves to that node to do the
* internal links. Afterwards, this routine provides recovery from that.
* The node needs to respond again using deflnk rather than routing, so
* that connections from other nodes to that one can be identified.
*
* @param[in] CurrentNode The node we are exploring from
* @param[in] State Access to Northbridge interface.
*
*/
VOID
STATIC
BackUpFromANode (
IN UINT8 CurrentNode,
IN STATE_DATA *State
)
{
if (CurrentNode != 0) {
// Disable routing tables on CurrentNode
State->Nb->DisableRoutingTables (CurrentNode, State->Nb);
}
}
/*----------------------------------------------------------------------------------------*/
/**
* Dynamically Discover all coherent devices in the system.
*
* @HtFeatMethod{::F_COHERENT_DISCOVERY}
*
* Initialize some basics like Node IDs and total Nodes found in the
* process. As we go we also build a representation of the discovered
* system which we will use later to program the routing tables.
* During this step, the routing is via default Link back to BSP and
* to each new Node on the Link it was discovered on (no coherency is
* active yet).
*
* In the case of multiple nodes per processor, do a one deep exploration of internal links
* to ensure those node pairs are always numbered n, n + 1.
*
* @param[in,out] State our global state
*
*/
VOID
CoherentDiscovery (
IN OUT STATE_DATA *State
)
{
UINT8 CurrentNode;
UINT8 OneDeepNode;
UINT8 OneDeepLink;
UINT8 CurrentLink;
UINT8 LogicalProcessor;
EXPLORE_NODE_STATUS ExplorationStatus;
LINK_ITERATOR_STATUS LinkIteratorStatus;
NEW_NODE_SAVED_INFO_ITEM NewNodeSavedInfoItems [MAX_NODES];
NEW_NODE_SAVED_INFO_LIST NewNodeSavedInfo;
// Initially no info exists for any node, but the BSP is part of logical processor zero.
for (CurrentNode = 0; CurrentNode < MAX_NODES; CurrentNode++) {
NewNodeSavedInfoItems [CurrentNode] = NoInfoSavedYet;
}
NewNodeSavedInfoItems[0].LogicalProcessor = 0;
NewNodeSavedInfoItems[0].HardwareSocket = State->Nb->GetSocket (0, 0, State->Nb);
State->Nb->GetModuleInfo (0, &NewNodeSavedInfoItems[0].NewModuleType, &NewNodeSavedInfoItems[0].NewModule, State->Nb);
NewNodeSavedInfo = (NEW_NODE_SAVED_INFO_LIST) NewNodeSavedInfoItems;
CurrentNode = 0;
CurrentLink = LINK_ITERATOR_BEGIN;
LogicalProcessor = 0;
// An initial status, for node zero if you will.
ExplorationStatus = ExploreNodeStatusGood;
//
// Entries are always added in pairs, the even indices are the 'source'
// side closest to the BSP, the odd indices are the 'destination' side
//
while ((CurrentNode <= State->NodesDiscovered) && (ExplorationStatus != ExploreNodeStatusStop)) {
StartFromANewNode (CurrentNode, State);
//
// Explore all internal links
//
LinkIteratorStatus = State->Nb->GetNextLink (CurrentNode, &CurrentLink, State->Nb);
while ((LinkIteratorStatus == LinkIteratorInternal) &&
(ExplorationStatus != ExploreNodeStatusStop)) {
if (IsLinkToAdd (CurrentNode, CurrentLink, State)) {
ExplorationStatus = ExploreNode (CurrentNode, CurrentLink, LogicalProcessor, NewNodeSavedInfo, State);
if ((ExplorationStatus == ExploreNodeStatusGood) ||
(ExplorationStatus == ExploreNodeStatusNew)) {
AddLinkToSystem (CurrentNode, CurrentLink, (CurrentNode + 1), State);
}
}
LinkIteratorStatus = State->Nb->GetNextLink (CurrentNode, &CurrentLink, State->Nb);
}
if (CurrentNode == 0) {
// The BSP processor is completely discovered now.
ProcessSavedNodeInfo (LogicalProcessor, NewNodeSavedInfo, State);
LogicalProcessor++;
}
//
// Explore all the external links from this node.
//
// Starting this iteration using the link that we last got in the iteration above.
while ((LinkIteratorStatus == LinkIteratorExternal) &&
(ExplorationStatus != ExploreNodeStatusStop)) {
if (IsLinkToAdd (CurrentNode, CurrentLink, State)) {
ExplorationStatus = ExploreNode (CurrentNode, CurrentLink, LogicalProcessor, NewNodeSavedInfo, State);
if (ExplorationStatus == ExploreNodeStatusNew) {
AddLinkToSystem (CurrentNode, CurrentLink, (CurrentNode + 1), State);
// If this is a new node, we need to explore to its internal mate, if any.
// This allows us to keep internal node pairs as ids n, n+1
// We use special link and node variables so we can keep our context.
OneDeepLink = 0xFF;
OneDeepNode = State->Nb->ReadToken ((CurrentNode + 1), State->Nb);
StartFromANewNode (OneDeepNode, State);
LinkIteratorStatus = State->Nb->GetNextLink (OneDeepNode, &OneDeepLink, State->Nb);
while ((LinkIteratorStatus == LinkIteratorInternal) &&
(ExplorationStatus != ExploreNodeStatusStop)) {
if (IsLinkToAdd (OneDeepNode, OneDeepLink, State)) {
ExplorationStatus = ExploreNode (OneDeepNode, OneDeepLink, LogicalProcessor, NewNodeSavedInfo, State);
if ((ExplorationStatus == ExploreNodeStatusGood) ||
(ExplorationStatus == ExploreNodeStatusNew)) {
AddLinkToSystem (OneDeepNode, OneDeepLink, (OneDeepNode + 1), State);
}
}
LinkIteratorStatus = State->Nb->GetNextLink (OneDeepNode, &OneDeepLink, State->Nb);
}
// Since we completed all the node's internal links, we found all the nodes in that processor.
ProcessSavedNodeInfo (LogicalProcessor, NewNodeSavedInfo, State);
LogicalProcessor++;
// Restore node to discoverable state. Otherwise you can't tell what links it is connected on.
BackUpFromANode (OneDeepNode, State);
} else {
if (ExplorationStatus == ExploreNodeStatusGood) {
AddLinkToSystem (CurrentNode, CurrentLink, (CurrentNode + 1), State);
}
}
}
LinkIteratorStatus = State->Nb->GetNextLink (CurrentNode, &CurrentLink, State->Nb);
}
CurrentNode++;
}
}