diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f15/Proc/HT/Features')
16 files changed, 4327 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatDynamicDiscovery.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatDynamicDiscovery.c new file mode 100644 index 0000000000..c42697ac17 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatDynamicDiscovery.c @@ -0,0 +1,783 @@ +/* $NoKeywords:$ */ +/** + * @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: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#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++; + } +} diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatDynamicDiscovery.h b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatDynamicDiscovery.h new file mode 100644 index 0000000000..25cbfdf0ef --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatDynamicDiscovery.h @@ -0,0 +1,80 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Coherent Discovery Interface. + * + * Contains interface to the coherent discovery feature. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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. +* +* *************************************************************************** +* +*/ + +#ifndef _HT_FEAT_DYNAMIC_DISCOVERY_H_ +#define _HT_FEAT_DYNAMIC_DISCOVERY_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +/** + * Dynamically Discover all coherent devices in the system. + * + */ +VOID +CoherentDiscovery ( + IN OUT STATE_DATA *State + ); + +#endif /* _HT_FEAT_DYNAMIC_DISCOVERY_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatGanging.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatGanging.c new file mode 100644 index 0000000000..533d376871 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatGanging.c @@ -0,0 +1,218 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Routines for re-ganging Links. + * + * Implement the reganging feature. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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 "amdlib.h" +#include "Ids.h" +#include "Topology.h" +#include "htFeat.h" +#include "htInterface.h" +#include "htNb.h" +#include "htFeatGanging.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_HT_FEATURES_HTFEATGANGING_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*************************************************************************** + *** Link Optimization *** + ***************************************************************************/ + +/*----------------------------------------------------------------------------------------*/ +/** + * Test the subLinks of a Link to see if they qualify to be reganged. + * + * @HtFeatMethod{::F_REGANG_LINKS} + * + * If they do, update the port list data to indicate that this should be done. + * @note no actual hardware state is changed in this routine. + * + * @param[in,out] State Our global state + */ +VOID +RegangLinks ( + IN OUT STATE_DATA *State + ) +{ + FINAL_LINK_STATE FinalLinkState; + UINT8 i; + UINT8 j; + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + // Data validation + ASSERT ((*State->PortList)[i].Type < 2 && (*State->PortList)[i].Link < State->Nb->MaxLinks); + ASSERT ((*State->PortList)[i + 1].Type < 2 && (*State->PortList)[i + 1].Link < State->Nb->MaxLinks); + + // Regang is false unless we pass all conditions below + (*State->PortList)[i].SelRegang = FALSE; + (*State->PortList)[i + 1].SelRegang = FALSE; + + // Only process cpu to cpu Links + if ( ((*State->PortList)[i].Type != PORTLIST_TYPE_CPU) || + ((*State->PortList)[i + 1].Type != PORTLIST_TYPE_CPU)) { + continue; + } + + for (j = i + 2; j < State->TotalLinks*2; j += 2) { + // Only process cpu to cpu Links + if ( ((*State->PortList)[j].Type != PORTLIST_TYPE_CPU) || + ((*State->PortList)[j + 1].Type != PORTLIST_TYPE_CPU) ) { + continue; + } + + // Links must be from the same source + if ((*State->PortList)[i].NodeID != (*State->PortList)[j].NodeID) { + continue; + } + + // Link must be to the same target + if ((*State->PortList)[i + 1].NodeID != (*State->PortList)[j + 1].NodeID) { + continue; + } + + // Ensure same source base port + if (((*State->PortList)[i].Link & 3) != ((*State->PortList)[j].Link & 3)) { + continue; + } + + // Ensure same destination base port + if (((*State->PortList)[i + 1].Link & 3) != ((*State->PortList)[j + 1].Link & 3)) { + continue; + } + + // Ensure subLink0 routes to subLink0 + if (((*State->PortList)[i].Link & 4) != ((*State->PortList)[i + 1].Link & 4)) { + continue; + } + + // (therefore subLink1 routes to subLink1) + ASSERT (((*State->PortList)[j].Link & 4) == ((*State->PortList)[j + 1].Link & 4)); + + FinalLinkState = State->HtInterface->GetSkipRegang ((*State->PortList)[i].NodeID, + (*State->PortList)[i].Link & 0x03, + (*State->PortList)[i + 1].NodeID, + (*State->PortList)[i + 1].Link & 0x03, + State); + if (FinalLinkState == MATCHED) { + continue; + } else if (FinalLinkState == POWERED_OFF) { + // StopLink will be done on the sublink 1, thus OR in 4 to the link to ensure it. + State->Nb->StopLink ((*State->PortList)[i].NodeID, ((*State->PortList)[i].Link | 4), State, State->Nb); + State->Nb->StopLink ((*State->PortList)[i + 1].NodeID, ((*State->PortList)[i + 1].Link | 4), State, State->Nb); + } + + // + // Create a ganged portlist entry for the two regang-able subLinks. + // + // All info will be that of subLink zero. + // (If Link discovery order was other than ascending, fix the .Pointer field too.) + // + // + if (((*State->PortList)[i].Link & 4) != 0) { + (*State->PortList)[i].Pointer = (*State->PortList)[j].Pointer; + (*State->PortList)[i + 1].Pointer = (*State->PortList)[j + 1].Pointer; + } + (*State->PortList)[i].Link &= 0x03; // Force to point to subLink0 + (*State->PortList)[i + 1].Link &= 0x03; + // If powered off, sublink 1 is removed but the link is still 8 bits. + if (FinalLinkState != POWERED_OFF) { + (*State->PortList)[i].SelRegang = TRUE; // Enable Link reganging + (*State->PortList)[i + 1].SelRegang = TRUE; + (*State->PortList)[i].PrvWidthOutCap = HT_WIDTH_16_BITS; + (*State->PortList)[i + 1].PrvWidthOutCap = HT_WIDTH_16_BITS; + (*State->PortList)[i].PrvWidthInCap = HT_WIDTH_16_BITS; + (*State->PortList)[i + 1].PrvWidthInCap = HT_WIDTH_16_BITS; + } + + // Delete PortList[j, j + 1], slow but easy to debug implementation + State->TotalLinks--; + LibAmdMemCopy (&((*State->PortList)[j]), + &((*State->PortList)[j + 2]), + sizeof (PORT_DESCRIPTOR)*(State->TotalLinks* 2 - j), + State->ConfigHandle); + LibAmdMemFill (&((*State->PortList)[State->TotalLinks * 2]), INVALID_LINK, (sizeof (PORT_DESCRIPTOR) * 2), State->ConfigHandle); + + break; // Exit loop, advance to PortList[i + 2] + } + } +} diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatGanging.h b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatGanging.h new file mode 100644 index 0000000000..988a4cfdb3 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatGanging.h @@ -0,0 +1,81 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Link Reganging Interface. + * + * Contains interface to the Reganging feature. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $ + * + */ +/* + *----------------------------------------------------------------------------- + ***************************************************************************** + * + * Copyright (C) 2012 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. + * + * *************************************************************************** + * + */ + +#ifndef _HT_FEAT_GANGING_H_ +#define _HT_FEAT_GANGING_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +/** + * Test the subLinks of a Link to see if they qualify to be reganged. + * + */ +VOID +RegangLinks ( + IN OUT STATE_DATA *State + ); + +#endif /* _HT_FEAT_GANGING_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatNoncoherent.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatNoncoherent.c new file mode 100644 index 0000000000..bde99c8dc9 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatNoncoherent.c @@ -0,0 +1,375 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Non-Coherent Discovery Routines. + * + * Contains routines for enumerating and initializing non-coherent devices. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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 "amdlib.h" +#include "Ids.h" +#include "Topology.h" +#include "htFeat.h" +#include "htInterface.h" +#include "htNotify.h" +#include "htNb.h" +#include "htFeatNoncoherent.h" +#include "htFeatOptimization.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_HT_FEATURES_HTFEATNONCOHERENT_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ +#define NO_DEVICE 0xFFFFFFFFull + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*************************************************************************** + *** Non-coherent init code *** + *** Algorithms *** + ***************************************************************************/ +/*----------------------------------------------------------------------------------------*/ +/** + * Process a non-coherent Link. + * + * @HtFeatMethod{::F_PROCESS_LINK} + * + * Enable a range of bus numbers, and set the device ID for all devices found. Add + * non-coherent devices, links to the system data structure. + * + * @param[in] Node Node on which to process nc init + * @param[in] Link The non-coherent Link on that Node + * @param[in] IsCompatChain Is this the chain with the southbridge? TRUE if yes. + * @param[in,out] State our global state + */ +VOID +ProcessLink ( + IN UINT8 Node, + IN UINT8 Link, + IN BOOLEAN IsCompatChain, + IN OUT STATE_DATA *State + ) +{ + UINT8 SecBus; + UINT8 SubBus; + UINT32 CurrentBuid; + UINT32 Temp; + UINT32 UnitIdCount; + PCI_ADDR CurrentPtr; + PCI_ADDR Link1ControlRegister; + UINT8 Depth; + BUID_SWAP_LIST *SwapPtr; + UINT8 LastLink; + BOOLEAN IsCaveDevice; + + ASSERT ((Node < MAX_NODES) && (Link < State->Nb->MaxLinks)); + + if (!State->HtInterface->GetOverrideBusNumbers (Node, Link, &SecBus, &SubBus, State)) { + // Assign Bus numbers + if (State->AutoBusCurrent >= State->HtBlock->AutoBusMax) { + // If we run out of Bus Numbers, notify and skip this chain + // + IDS_ERROR_TRAP; + NotifyErrorNcohBusMaxExceed (Node, Link, State->AutoBusCurrent, State); + return; + } + + if (State->UsedCfgMapEntries >= 4) { + // If we have used all the PCI Config maps we can't add another chain. + // Notify and if call back is unimplemented or returns, skip this chain. + // + IDS_ERROR_TRAP; + NotifyErrorNcohCfgMapExceed (Node, Link, State); + return; + } + + SecBus = State->AutoBusCurrent; + SubBus = SecBus + State->HtBlock->AutoBusIncrement - 1; + State->AutoBusCurrent = State->AutoBusCurrent + State->HtBlock->AutoBusIncrement; + } + + State->Nb->SetConfigAddrMap (State->UsedCfgMapEntries, SecBus, SubBus, Node, Link, State, State->Nb); + State->UsedCfgMapEntries++; + + if (State->HtInterface->GetManualBuidSwapList (Node, Link, &SwapPtr, State)) { + // Manual non-coherent BUID assignment + AGESA_TESTPOINT (TpProcHtManualNc, State->ConfigHandle); + + + if (!IsCompatChain || !State->IsUsingRecoveryHt) { + // If this is the not southbridge chain or Recovery HT was not used + // then we need to assign BUIDs here. + // + Depth = 0; + // Assign BUID's per manual override + while (SwapPtr->Swaps[Depth].FromId != 0xFF) { + CurrentPtr.AddressValue = MAKE_SBDFO (0, SecBus, SwapPtr->Swaps[Depth].FromId, 0, 0); + if (DoesDeviceHaveHtSubtypeCap (CurrentPtr, HT_SLAVE_CAPABILITY, &CurrentPtr, State)) { + // Set the device's BUID field [20:16] to the current buid + CurrentBuid = SwapPtr->Swaps[Depth].ToId; + LibAmdPciWriteBits (CurrentPtr, 20, 16, &CurrentBuid, State->ConfigHandle); + Depth++; + } else { + // All non-coherent devices must have a slave interface capability. + ASSERT (FALSE); + break; + } + } + } + + // Build chain of devices. Do this even if Recovery HT assign BUIDs for this chain. + Depth = 0; + while (SwapPtr->FinalIds[Depth] != 0xFF) { + ASSERT (State->TotalLinks < MAX_PLATFORM_LINKS); + (*State->PortList)[(State->TotalLinks * 2)].NodeID = Node; + // Note: depth == 0 is true before depth > 0. This makes LastLink variable work. + if (Depth == 0) { + (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_CPU; + (*State->PortList)[(State->TotalLinks * 2)].Link = Link; + } else { + // Fill in the host side port. Link and base pointer can be deduced from the upstream link's + // downstream port. + (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_IO; + (*State->PortList)[(State->TotalLinks * 2)].Link = 1 - (*State->PortList)[(((State->TotalLinks - 1) * 2) + 1)].Link; + (*State->PortList)[(State->TotalLinks * 2)].HostLink = Link; + (*State->PortList)[(State->TotalLinks * 2)].HostDepth = Depth - 1; + (*State->PortList)[(State->TotalLinks * 2)].Pointer = (*State->PortList)[(((State->TotalLinks - 1) * 2) + 1)].Pointer; + } + + (*State->PortList)[(State->TotalLinks * 2) + 1].Type = PORTLIST_TYPE_IO; + (*State->PortList)[(State->TotalLinks * 2) + 1].NodeID = Node; + (*State->PortList)[(State->TotalLinks * 2) + 1].HostLink = Link; + (*State->PortList)[(State->TotalLinks * 2) + 1].HostDepth = Depth; + + CurrentPtr.AddressValue = MAKE_SBDFO (0, SecBus, (SwapPtr->FinalIds[Depth] & 0x3F), 0, 0); + if (DoesDeviceHaveHtSubtypeCap (CurrentPtr, HT_SLAVE_CAPABILITY, &CurrentPtr, State)) { + (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr; + } else { + // All non-coherent devices must have a slave interface capability. + ASSERT (FALSE); + break; + } + + // Bit 6 indicates whether orientation override is desired. + // Bit 7 indicates the upstream Link if overriding. + // + // assert catches at least the one known incorrect setting, that a non-zero link + // is specified, but override desired is not set. + ASSERT (((SwapPtr->FinalIds[Depth] & 0x40) != 0) || ((SwapPtr->FinalIds[Depth] & 0x80) == 0)); + if ((SwapPtr->FinalIds[Depth] & 0x40) != 0) { + // Override the device's orientation + LastLink = SwapPtr->FinalIds[Depth] >> 7; + } else { + // Detect the device's orientation, by reading the Master Host bit [26] + LibAmdPciReadBits (CurrentPtr, 26, 26, &Temp, State->ConfigHandle); + LastLink = (UINT8)Temp; + } + (*State->PortList)[(State->TotalLinks * 2) + 1].Link = LastLink; + + Depth++; + State->TotalLinks++; + } + } else { + // Automatic non-coherent device detection + AGESA_TESTPOINT (TpProcHtAutoNc, State->ConfigHandle); + IDS_HDT_CONSOLE (HT_TRACE, "Auto IO chain init on node=%d, link=%d, secbus=%d, subbus=%d%s.\n", + Node, Link, SecBus, SubBus, (IsCompatChain ? ", Compat" : "")); + Depth = 0; + CurrentBuid = 1; + for (; ; ) { + CurrentPtr.AddressValue = MAKE_SBDFO (0, SecBus, 0, 0, 0); + + LibAmdPciRead (AccessWidth32, CurrentPtr, &Temp, State->ConfigHandle); + if (Temp == NO_DEVICE) { + if (IsCompatChain && State->IsUsingRecoveryHt) { + // See if the device is aleady at a non-zero BUID because HT Init Reset aleady assigned it. + CurrentPtr.Address.Device = CurrentBuid; + LibAmdPciRead (AccessWidth32, CurrentPtr, &Temp, State->ConfigHandle); + if (Temp == NO_DEVICE) { + // No more devices already assigned. + break; + } + } else { + // No more devices found. + break; + } + } + + ASSERT (State->TotalLinks < MAX_PLATFORM_LINKS); + + (*State->PortList)[(State->TotalLinks * 2)].NodeID = Node; + if (Depth == 0) { + (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_CPU; + (*State->PortList)[(State->TotalLinks * 2)].Link = Link; + } else { + // Fill in the host side port. Link and base pointer can be deduced from the upstream link's + // downstream port. + (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_IO; + (*State->PortList)[(State->TotalLinks * 2)].Link = 1 - (*State->PortList)[((State->TotalLinks - 1) * 2) + 1].Link; + (*State->PortList)[(State->TotalLinks * 2)].HostLink = Link; + (*State->PortList)[(State->TotalLinks * 2)].HostDepth = Depth - 1; + (*State->PortList)[(State->TotalLinks * 2)].Pointer = (*State->PortList)[((State->TotalLinks - 1) * 2) + 1].Pointer; + } + + (*State->PortList)[(State->TotalLinks * 2) + 1].Type = PORTLIST_TYPE_IO; + (*State->PortList)[(State->TotalLinks * 2) + 1].NodeID = Node; + (*State->PortList)[(State->TotalLinks * 2) + 1].HostLink = Link; + (*State->PortList)[(State->TotalLinks * 2) + 1].HostDepth = Depth; + + if (DoesDeviceHaveHtSubtypeCap (CurrentPtr, HT_SLAVE_CAPABILITY, &CurrentPtr, State)) { + + // Get device's unit id count [25:21] + LibAmdPciReadBits (CurrentPtr, 25, 21, &UnitIdCount, State->ConfigHandle); + if (((UnitIdCount + CurrentBuid) > MAX_BUID) || ((SecBus == 0) && ((UnitIdCount + CurrentBuid) > 24))) { + // An error handler for the case where we run out of BUID's on a chain + NotifyErrorNcohBuidExceed (Node, Link, Depth, (UINT8)CurrentBuid, (UINT8)UnitIdCount, State); + IDS_ERROR_TRAP; + break; + } + // While we are still certain we are accessing this device, remember if it is a cave device. + // This is found by reading EOC from the Link 1 Control Register. + Link1ControlRegister = CurrentPtr; + Link1ControlRegister.Address.Register += (HTSLAVE_LINK01_OFFSET + HTSLAVE_LINK_CONTROL_0_REG); + LibAmdPciReadBits (Link1ControlRegister, 6, 6, &Temp, State->ConfigHandle); + IsCaveDevice = ((Temp == 0) ? FALSE : TRUE); + + // Attempt to write the new BUID. Unless this chain was aleady assigned BUIDs during Init Reset, + // then just re-discover the chain. Note this may be true whether the device was found at + // BUID zero or not. + IDS_HDT_CONSOLE (HT_TRACE, "Found device at depth=%d, BUID=%d.\n", Depth, CurrentPtr.Address.Device); + if (!IsCompatChain || !State->IsUsingRecoveryHt) { + IDS_HDT_CONSOLE (HT_TRACE, "Assigning device to BUID=%d.\n", CurrentBuid); + LibAmdPciWriteBits (CurrentPtr, 20, 16, &CurrentBuid, State->ConfigHandle); + } + + CurrentPtr.Address.Device = CurrentBuid; + LibAmdPciReadBits (CurrentPtr, 20, 16, &Temp, State->ConfigHandle); + if (Temp != CurrentBuid) { + if ((Depth == 0) && IsCaveDevice) { + // If the chain only consists of a single cave device, that device may have retained zero + // for it's BUID. + CurrentPtr.Address.Device = 0; + LibAmdPciReadBits (CurrentPtr, 20, 16, &Temp, State->ConfigHandle); + if (Temp == 0) { + // Per HyperTransport specification, devices not accepting BUID reassignment hardwire BUID to zero. + (*State->PortList)[(State->TotalLinks * 2) + 1].Link = 0; + (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr; + State->TotalLinks++; + Depth++; + // Success! + IDS_HDT_CONSOLE (HT_TRACE, "%s Cave left at BUID=0.\n", ((!IsCompatChain || !State->IsUsingRecoveryHt) ? "Compatible" : "Already Assigned")); + break; + } else if (Temp == CurrentBuid) { + // and then, there are the other kind of devices .... + // Restore the writable BUID field (which contains the value we just wrote) to zero. + Temp = 0; + LibAmdPciWriteBits (CurrentPtr, 20, 16, &Temp, State->ConfigHandle); + (*State->PortList)[(State->TotalLinks * 2) + 1].Link = 0; + (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr; + State->TotalLinks++; + Depth++; + // Success! + IDS_HDT_CONSOLE (HT_TRACE, "Cave left at BUID=0.\n"); + break; + } + } + // An error handler for this error, + // this often occurs in new BIOS ports and it means you need to use a Manual BUID Swap List. + NotifyErrorNcohDeviceFailed (Node, Link, Depth, (UINT8)CurrentBuid, State); + IDS_ERROR_TRAP; + break; + } + + LibAmdPciReadBits (CurrentPtr, 26, 26, &Temp, State->ConfigHandle); + (*State->PortList)[(State->TotalLinks * 2) + 1].Link = (UINT8)Temp; + (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr; + + IDS_HDT_CONSOLE (HT_TRACE, "Device assigned.\n"); + Depth++; + State->TotalLinks++; + CurrentBuid += UnitIdCount; + } else { + // All non-coherent devices must have a slave interface capability. + ASSERT (FALSE); + break; + } + } + // Provide information on automatic device results + NotifyInfoNcohAutoDepth (Node, Link, (Depth - 1), State); + } +} diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatNoncoherent.h b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatNoncoherent.h new file mode 100644 index 0000000000..7293fbb8da --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatNoncoherent.h @@ -0,0 +1,81 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Non-Coherent Discovery Interface. + * + * Contains interface to the Non-Coherent Link processing feature. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $ + * + */ +/* + ***************************************************************************** + * + * Copyright (C) 2012 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. + * + * *************************************************************************** + * + */ + +#ifndef _HT_FEAT_NONCOHERENT_H_ +#define _HT_FEAT_NONCOHERENT_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +/** + * Process a non-coherent Link. + * + */ +VOID +ProcessLink ( + IN UINT8 Node, + IN UINT8 Link, + IN BOOLEAN IsCompatChain, + IN OUT STATE_DATA *State + ); + +#endif /* _HT_FEAT_NONCOHERENT_H_ */ diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatOptimization.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatOptimization.c new file mode 100644 index 0000000000..c1e20bde3f --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatOptimization.c @@ -0,0 +1,890 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Link Optimization Routines. + * + * Contains routines for determining width, frequency, and other + * Link features + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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 "amdlib.h" +#include "Ids.h" +#include "Topology.h" +#include "htFeat.h" +#include "IdsHt.h" +#include "htInterface.h" +#include "htNb.h" +#include "htFeatOptimization.h" +#include "htNotify.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_HT_FEATURES_HTFEATOPTIMIZATION_FILECODE + +extern CONST PF_HtIdsGetPortOverride ROMDATA pf_HtIdsGetPortOverride; + +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ +#define PCI_CONFIG_COMMAND_REG04 4 +#define PCI_CONFIG_REVISION_REG08 8 + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*************************************************************************** + *** Link Optimization *** + ***************************************************************************/ + +/*----------------------------------------------------------------------------------------*/ +/** + * Given the bits set in the register field, return the width it represents. + * + * As invalid width values or encodings are rare except during debug, catch those using + * ASSERT(). This means theoretically we are returning an incorrect result if that + * happens. The default chosen for the result is arbitrarily 8 bits. This is likely + * not to be the actual correct width and may cause a crash, hang, or incorrect operation. + * Hardware often ignores writes of invalid width encodings. + * + * @note This routine is used for CPUs as well as IO devices, as all comply to the + * "HyperTransport I/O Link Specification ". + * + * @param[in] Value The bits for the register + * + * @return The width + */ +UINT8 +STATIC +ConvertBitsToWidth ( + IN UINT8 Value + ) +{ + UINT8 Result; + + Result = 0; + + switch (Value) { + + case 1: + Result = 16; + break; + + case 0: + Result = 8; + break; + + case 3: + Result = 32; + break; + + case 5: + Result = 4; + break; + + case 4: + Result = 2; + break; + + default: + ASSERT (FALSE); + } + return Result; +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Translate a desired width setting to the bits to set in the register field. + * + * As invalid width values or encodings are rare except during debug, catch those using + * ASSERT(). This means theoretically we are returning an incorrect result if that + * happens. The default chosen for the result is arbitrarily 8 bits. This is likely + * not to be the actual correct width and may cause a crash, hang, or incorrect operation. + * Hardware often ignores writes of invalid width encodings. + * + * @note This routine is used for CPUs as well as IO devices, as all comply to the + * "HyperTransport I/O Link Specification ". + * + * @param[in] Value the width Value + * + * @return The bits for the register + */ +UINT8 +ConvertWidthToBits ( + IN UINT8 Value + ) +{ + UINT8 Result; + + Result = 8; + + switch (Value) { + + case 16: + Result = 1; + break; + + case 8: + Result = 0; + break; + + case 32: + Result = 3; + break; + + case 4: + Result = 5; + break; + + case 2: + Result = 4; + break; + + default: + ASSERT (FALSE); + } + return Result; +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Access HT Link Control Register. + * + * @HtFeatMethod{::F_SET_HT_CONTROL_REGISTER_BITS} + * + * Provide a common routine for accessing the HT Link Control registers (84, a4, c4, + * e4), to enforce not clearing the HT CRC error bits. Replaces direct use of + * AmdPCIWriteBits(). + * + * @note: This routine is called for CPUs as well as IO Devices! All comply to the + * "HyperTransport I/O Link Specification ". + * + * @param[in] Reg the PCI config address the control register + * @param[in] HiBit the high bit number + * @param[in] LoBit the low bit number + * @param[in] Value the value to write to that bit range. Bit 0 => loBit. + * @param[in] State Our state, config handle for lib + */ +VOID +SetHtControlRegisterBits ( + IN PCI_ADDR Reg, + IN UINT8 HiBit, + IN UINT8 LoBit, + IN UINT32 *Value, + IN STATE_DATA *State + ) +{ + UINT32 Temp; + UINT32 mask; + + ASSERT ((HiBit < 32) && (LoBit < 32) && (HiBit >= LoBit) && ((Reg.AddressValue & 0x3) == 0)); + ASSERT ((HiBit < 8) || (LoBit > 9)); + + // A 1 << 32 == 1 << 0 due to x86 SHL instruction, so skip if that is the case + if ((HiBit - LoBit) != 31) { + mask = (((UINT32)1 << (HiBit - LoBit + 1)) - 1); + } else { + mask = (UINT32)0xFFFFFFFF; + } + + LibAmdPciRead (AccessWidth32, Reg, &Temp, State->ConfigHandle); + Temp &= ~(mask << LoBit); + Temp |= (*Value & mask) << LoBit; + Temp &= (UINT32)HT_CONTROL_CLEAR_CRC; + LibAmdPciWrite (AccessWidth32, Reg, &Temp, State->ConfigHandle); +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Set HT Frequency register for IO Devices + * + * Provide a common routine for accessing the HT Link Frequency registers at offset 8 + * and 0x10, to enforce not clearing the HT Link error bits. Replaces direct use of + * AmdPCIWriteBits(). + * + * @note This routine is called for IO Devices only!! All comply to the + * "HyperTransport I/O Link Specification ". + * + * @param[in] Reg the PCI config address the control register + * @param[in] Hibit the high bit number + * @param[in] Lobit the low bit number + * @param[in] Value the value to write to that bit range. Bit 0 => loBit. + * @param[in] State Our state, config handle for lib + */ +VOID +STATIC +SetHtIoFrequencyRegisterBits ( + IN PCI_ADDR Reg, + IN UINT8 Hibit, + IN UINT8 Lobit, + IN UINT32 *Value, + IN STATE_DATA *State + ) +{ + UINT32 Mask; + UINT32 Temp; + + ASSERT ((Hibit < 32) && (Lobit < 32) && (Hibit >= Lobit) && ((Reg.AddressValue & 0x3) == 0)); + ASSERT ((Hibit < 12) || (Lobit > 14)); + + // A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case + if ((Hibit - Lobit) != 31) { + Mask = (((UINT32)1 << ((Hibit - Lobit) + 1)) - 1); + } else { + Mask = (UINT32)0xFFFFFFFF; + } + + LibAmdPciRead (AccessWidth32, Reg, &Temp, State->ConfigHandle); + Temp &= ~(Mask << Lobit); + Temp |= (*Value & Mask) << Lobit; + Temp &= (UINT32)HT_FREQUENCY_CLEAR_LINK_ERRORS; + LibAmdPciWrite (AccessWidth32, Reg, &Temp, State->ConfigHandle); +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Get Link features into system data structure. + * + * @HtFeatMethod{::F_GATHER_LINK_DATA} + * + * For all discovered Links, populate the port list with the frequency and width + * capabilities. Gather support data for: + * - Unit ID Clumping + * + * @param[in] State our global state, port list + */ +VOID +GatherLinkData ( + IN STATE_DATA *State + ) +{ + UINT8 i; + PCI_ADDR LinkBase; + PCI_ADDR Reg; + UINT32 Bits; + UINT8 Revision; + + // Get the capability base for whatever device type the link port is on + for (i = 0; i < (State->TotalLinks * 2); i++) { + if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) { + LinkBase = State->Nb->MakeLinkBase ((*State->PortList)[i].NodeID, (*State->PortList)[i].Link, State->Nb); + (*State->PortList)[i].Pointer = LinkBase; + } else { + LinkBase = (*State->PortList)[i].Pointer; + if ((*State->PortList)[i].Link == 1) { + LinkBase.Address.Register += HTSLAVE_LINK01_OFFSET; + } + } + + // Getting the Width is standard across device types + Reg = LinkBase; + Reg.Address.Register += HTSLAVE_LINK_CONTROL_0_REG; + LibAmdPciReadBits (Reg, 22, 20, &Bits, State->ConfigHandle); + (*State->PortList)[i].PrvWidthOutCap = ConvertBitsToWidth ((UINT8)Bits); + + LibAmdPciReadBits (Reg, 18, 16, &Bits, State->ConfigHandle); + (*State->PortList)[i].PrvWidthInCap = ConvertBitsToWidth ((UINT8)Bits); + + // Get Frequency and other device type specific features + if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) { + State->Nb->GatherLinkFeatures (&(*State->PortList)[i], State->HtInterface, State->PlatformConfiguration, State->Nb); + } else { + Reg = LinkBase; + Reg.Address.Register += HTSLAVE_FREQ_REV_0_REG; + LibAmdPciReadBits (Reg, 31, 16, &Bits, State->ConfigHandle); + (*State->PortList)[i].PrvFrequencyCap = Bits; + + // Unit ID Clumping Support + if (State->IsUsingUnitIdClumping) { + if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_UNITID_CAPABILITY, &Reg, State)) { + Reg.Address.Register += HTUNIT_SUPPORT_REG; + LibAmdPciReadBits (Reg, 31, 0, &Bits, State->ConfigHandle); + } else { + // Not there, that's ok, we don't know that it should have one. + // Check for Passive support. (Bit 0 won't be set if full support is implemented, + // so we can use it to indicate passive support in our portlist struct). + Reg = LinkBase; + Reg.Address.Register += HTSLAVE_FEATURECAP_REG; + Bits = 1; + LibAmdPciWriteBits (Reg, 5, 5, &Bits, State->ConfigHandle); + LibAmdPciReadBits (Reg, 5, 5, &Bits, State->ConfigHandle); + } + (*State->PortList)[i].ClumpingSupport = Bits; + } else { + (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE; + } + + Reg = LinkBase; + Reg.Address.Register = PCI_CONFIG_REVISION_REG08; + LibAmdPciReadBits ( LinkBase, 7, 0, &Bits, State->ConfigHandle); + Revision = (UINT8) Bits; + + LinkBase.Address.Register = 0; + LibAmdPciRead (AccessWidth32, LinkBase, &Bits, State->ConfigHandle); + + State->HtInterface->GetDeviceCapOverride ((*State->PortList)[i].NodeID, + (*State->PortList)[i].HostLink, + (*State->PortList)[i].HostDepth, + (*State->PortList)[i].Pointer, + Bits, + Revision, + (*State->PortList)[i].Link, + &((*State->PortList)[i].PrvWidthInCap), + &((*State->PortList)[i].PrvWidthOutCap), + &((*State->PortList)[i].PrvFrequencyCap), + &((*State->PortList)[i].ClumpingSupport), + State); + } + } +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Optimize Links. + * + * @HtFeatMethod{::F_SELECT_OPTIMAL_WIDTH_AND_FREQUENCY} + * + * For all Links: + * Examine both sides of a Link and determine the optimal frequency and width, + * taking into account externally provided limits and enforcing any other limit + * or matching rules as applicable except subLink balancing. Update the port + * list data with the optimal settings. + * + * @note no hardware state changes in this routine. + * + * @param[in,out] State Process and update portlist + */ +VOID +SelectOptimalWidthAndFrequency ( + IN OUT STATE_DATA *State + ) +{ + UINT8 i; + UINT8 j; + UINT8 Freq; + UINT32 Temp; + UINT32 CbPcbFreqLimit; + UINT8 CbPcbABDownstreamWidth; + UINT8 CbPcbBAUpstreamWidth; + + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + CbPcbFreqLimit = HT_FREQUENCY_NO_LIMIT; + CbPcbABDownstreamWidth = HT_WIDTH_16_BITS; + CbPcbBAUpstreamWidth = HT_WIDTH_16_BITS; + + if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { + State->HtInterface->GetCpu2CpuPcbLimits ((*State->PortList)[i].NodeID, + (*State->PortList)[i].Link, + (*State->PortList)[i + 1].NodeID, + (*State->PortList)[i + 1].Link, + &CbPcbABDownstreamWidth, + &CbPcbBAUpstreamWidth, + &CbPcbFreqLimit, + State + ); + } else { + State->HtInterface->GetIoPcbLimits ((*State->PortList)[i + 1].NodeID, + (*State->PortList)[i + 1].HostLink, + (*State->PortList)[i + 1].HostDepth, + &CbPcbABDownstreamWidth, + &CbPcbBAUpstreamWidth, + &CbPcbFreqLimit, + State + ); + } + + Temp = (*State->PortList)[i].PrvFrequencyCap; + Temp &= (*State->PortList)[i + 1].PrvFrequencyCap; + Temp &= CbPcbFreqLimit; + (*State->PortList)[i].CompositeFrequencyCap = (UINT32)Temp; + (*State->PortList)[i + 1].CompositeFrequencyCap = (UINT32)Temp; + + ASSERT (Temp != 0); + Freq = LibAmdBitScanReverse (Temp); + (*State->PortList)[i].SelFrequency = Freq; + (*State->PortList)[i + 1].SelFrequency = Freq; + + Temp = (*State->PortList)[i].PrvWidthOutCap; + if ((*State->PortList)[i + 1].PrvWidthInCap < Temp) { + Temp = (*State->PortList)[i + 1].PrvWidthInCap; + } + if (CbPcbABDownstreamWidth < Temp) { + Temp = CbPcbABDownstreamWidth; + } + (*State->PortList)[i].SelWidthOut = (UINT8)Temp; + (*State->PortList)[i + 1].SelWidthIn = (UINT8)Temp; + + Temp = (*State->PortList)[i].PrvWidthInCap; + if ((*State->PortList)[i + 1].PrvWidthOutCap < Temp) { + Temp = (*State->PortList)[i + 1].PrvWidthOutCap; + } + if (CbPcbBAUpstreamWidth < Temp) { + Temp = CbPcbBAUpstreamWidth; + } + (*State->PortList)[i].SelWidthIn = (UINT8)Temp; + (*State->PortList)[i + 1].SelWidthOut = (UINT8)Temp; + } + // Calculate unit id clumping + // + // Find the root of each IO Chain, process the chain for clumping support. + // The root is always the first link of the chain in the port list. + // Clumping is not device link specific, so we can just look at the upstream ports (j+1). Use ASSERTs to sanity + // check the downstream ports (j). If any device on the chain does not support clumping, the entire chain will be + // disabled for clumping. + // After analyzing the clumping support on the chain the CPU's portlist has the enable mask. Update all the + // IO Devices on the chain with the enable mask. If any device's only have passive support, that is already enabled. + // + if (State->IsUsingUnitIdClumping) { + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_IO)) { + (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE; + if ((*State->PortList)[i + 1].ClumpingSupport != HT_CLUMPING_DISABLE) { + (*State->PortList)[i].ClumpingSupport |= (*State->PortList)[i + 1].ClumpingSupport; + for (j = i + 2; j < (State->TotalLinks * 2); j += 2) { + if (((*State->PortList)[j].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[j + 1].Type == PORTLIST_TYPE_IO)) { + if (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) && + ((*State->PortList)[i].Link == (*State->PortList)[j + 1].HostLink)) { + ASSERT (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) && + ((*State->PortList)[i].Link == (*State->PortList)[j].HostLink)); + if ((*State->PortList)[j + 1].ClumpingSupport != HT_CLUMPING_DISABLE) { + ASSERT ((((*State->PortList)[j + 1].ClumpingSupport & HT_CLUMPING_PASSIVE) == 0) || + (((*State->PortList)[j + 1].ClumpingSupport & ~(HT_CLUMPING_PASSIVE)) == 0)); + (*State->PortList)[i].ClumpingSupport |= (*State->PortList)[j + 1].ClumpingSupport; + } else { + (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE; + break; + } + } + } + } + if ((*State->PortList)[i + 1].ClumpingSupport != HT_CLUMPING_PASSIVE) { + (*State->PortList)[i + 1].ClumpingSupport = (*State->PortList)[i].ClumpingSupport; + } + for (j = i + 2; j < (State->TotalLinks * 2); j += 2) { + if (((*State->PortList)[j].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[j + 1].Type == PORTLIST_TYPE_IO)) { + if (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) && + ((*State->PortList)[i].Link == (*State->PortList)[j + 1].HostLink)) { + if ((*State->PortList)[j + 1].ClumpingSupport != HT_CLUMPING_PASSIVE) { + (*State->PortList)[j + 1].ClumpingSupport = (*State->PortList)[i].ClumpingSupport; + // The downstream isn't really passive, just mark it so in order to write the device only once. + (*State->PortList)[j].ClumpingSupport = HT_CLUMPING_PASSIVE; + } + } + } + } + } + } + } + } +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Change the hardware state for all Links according to the now optimized data in the + * port list data structure. + * + * @HtFeatMethod{::F_SET_LINK_DATA} + * + * @param[in] State our global state, port list + */ +VOID +SetLinkData ( + IN STATE_DATA *State + ) +{ + UINT8 i; + PCI_ADDR LinkBase; + PCI_ADDR Reg; + UINT32 Temp; + UINT32 Widthin; + UINT32 Widthout; + UINT32 Bits; + PCI_ADDR CurrentPtr; + HTIDS_PORT_OVERRIDE_LIST PortOverrides; + + PortOverrides = NULL; + + for (i = 0; i < (State->TotalLinks * 2); i++) { + + ASSERT ((*State->PortList)[i & 0xFE].SelWidthOut == (*State->PortList)[ (i & 0xFE) + 1].SelWidthIn); + ASSERT ((*State->PortList)[i & 0xFE].SelWidthIn == (*State->PortList)[ (i & 0xFE) + 1].SelWidthOut); + ASSERT ((*State->PortList)[i & 0xFE].SelFrequency == (*State->PortList)[ (i & 0xFE) + 1].SelFrequency); + + if ((*State->PortList)[i].SelRegang) { + ASSERT ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU); + ASSERT ((*State->PortList)[i].Link < 4); + State->Nb->SetLinkRegang ( + (*State->PortList)[i].NodeID, + (*State->PortList)[i].Link, + State->Nb + ); + } + + // + // IDS port override for CPUs and IO Devices + // + pf_HtIdsGetPortOverride ((BOOLEAN) ((i & 1) == 0), &(*State->PortList)[i], &(*State->PortList)[i + 1], &PortOverrides, State); + + LinkBase = (*State->PortList)[i].Pointer; + if (((*State->PortList)[i].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[i].Link == 1)) { + LinkBase.Address.Register += HTSLAVE_LINK01_OFFSET; + } + + // HT CRC Feature, set if configured. The default is not to set it, because with some chipsets it + // will lock up if done here. + if (State->IsSetHtCrcFlood) { + Temp = 1; + Reg = LinkBase; + Reg.Address.Register += HTHOST_LINK_CONTROL_REG; + State->HtFeatures->SetHtControlRegisterBits (Reg, 1, 1, &Temp, State); + if ((*State->PortList)[i].Type == PORTLIST_TYPE_IO) { + // IO Devices also need to have SERR enabled. + Reg = LinkBase; + Reg.Address.Register = PCI_CONFIG_COMMAND_REG04; + LibAmdPciWriteBits (Reg, 8, 8, &Temp, State->ConfigHandle); + } + } + + // Some IO devices don't work properly when setting widths, so write them in a single operation, + // rather than individually. + // + Widthout = ConvertWidthToBits ((*State->PortList)[i].SelWidthOut); + ASSERT (Widthout == 1 || Widthout == 0 || Widthout == 5 || Widthout == 4); + Widthin = ConvertWidthToBits ((*State->PortList)[i].SelWidthIn); + ASSERT (Widthin == 1 || Widthin == 0 || Widthin == 5 || Widthin == 4); + + Temp = (Widthin & 7) | ((Widthout & 7) << 4); + Reg = LinkBase; + Reg.Address.Register += HTHOST_LINK_CONTROL_REG; + State->HtFeatures->SetHtControlRegisterBits (Reg, 31, 24, &Temp, State); + + Temp = (*State->PortList)[i].SelFrequency; + IDS_HDT_CONSOLE (HT_TRACE, "Link Frequency: Node %02d: Link %02d: is running at %2d00MHz\n", + (*State->PortList)[i].NodeID, (*State->PortList)[i].Link, + (Temp < HT_FREQUENCY_800M) ? Temp + 2 : ((Temp < HT_FREQUENCY_2800M) ? 2 * (Temp - 1) : 2 * (Temp - 3))); + + if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) { + State->Nb->SetLinkFrequency ( + (*State->PortList)[i].NodeID, + (*State->PortList)[i].Link, + (UINT8)Temp, + State->Nb + ); + } else { + ASSERT (Temp <= HT_FREQUENCY_2600M); + // Write the frequency setting + Reg = LinkBase; + Reg.Address.Register += HTSLAVE_FREQ_REV_0_REG; + SetHtIoFrequencyRegisterBits (Reg, 11, 8, &Temp, State); + + // Handle additional HT3 frequency requirements, if needed, + // or clear them if switching down to ht1 on a warm reset. + // Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz + // + // Even though we assert if debugging, we need to check that the capability was + // found always, since this is an unknown hardware device, also we are taking + // unqualified frequency from the external interface (could be trying to do ht3 + // on an ht1 IO device). + // + + if (Temp > HT_FREQUENCY_1000M) { + // Enabling features if gen 3 + Bits = 1; + } else { + // Disabling features if gen 1 + Bits = 0; + } + + // Retry Enable + if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_RETRY_CAPABILITY, &CurrentPtr, State)) { + ASSERT ((*State->PortList)[i].Link < 2); + CurrentPtr.Address.Register += HTRETRY_CONTROL_REG; + LibAmdPciWriteBits (CurrentPtr, + ((*State->PortList)[i].Link * 16), + ((*State->PortList)[i].Link * 16), + &Bits, + State->ConfigHandle); + } else { + // If we are turning it off, that may mean the device was only ht1 capable, + // so don't complain that we can't do it. + // + if (Bits != 0) { + NotifyWarningOptRequiredCapRetry ((*State->PortList)[i].NodeID, + (*State->PortList)[i].HostLink, + (*State->PortList)[i].HostDepth, + State); + } + } + + // Scrambling enable + if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_GEN3_CAPABILITY, &CurrentPtr, State)) { + ASSERT ((*State->PortList)[i].Link < 2); + CurrentPtr.Address.Register = CurrentPtr.Address.Register + + HTGEN3_LINK_TRAINING_0_REG + + ((*State->PortList)[i].Link * HTGEN3_LINK01_OFFSET); + LibAmdPciWriteBits (CurrentPtr, 3, 3, &Bits, State->ConfigHandle); + } else { + // If we are turning it off, that may mean the device was only ht1 capable, + // so don't complain that we can't do it. + // + if (Bits != 0) { + NotifyWarningOptRequiredCapGen3 ((*State->PortList)[i].NodeID, + (*State->PortList)[i].HostLink, + (*State->PortList)[i].HostDepth, + State); + } + } + } + // Enable Unit ID Clumping if supported. + if (State->IsUsingUnitIdClumping) { + if (((*State->PortList)[i].ClumpingSupport != HT_CLUMPING_PASSIVE) && + ((*State->PortList)[i].ClumpingSupport != HT_CLUMPING_DISABLE)) { + Bits = (*State->PortList)[i].ClumpingSupport; + if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) { + State->Nb->SetLinkUnitIdClumping ( + (*State->PortList)[i].NodeID, + (*State->PortList)[i].Link, + (*State->PortList)[i].ClumpingSupport, + State->Nb + ); + } else { + if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_UNITID_CAPABILITY, &Reg, State)) { + Reg.Address.Register += HTUNIT_ENABLE_REG; + LibAmdPciWriteBits (Reg, 31, 0, &Bits, State->ConfigHandle); + } else { + // If we found one when gathering support, we have to find one now. + ASSERT (FALSE); + } + } + } + } + } +} + +/*------------------------------------------------------------------------------------------*/ +/** + * Find a specific HT capability type. + * + * Search all the PCI Config space capabilities on any type of device for an + * HT capability of the specific subtype. + * + * @param[in] DevicePointer A PCI Config address somewhere in the device config space + * @param[in] CapSubType The HT capability subtype to find + * @param[out] CapabilityBase The Config space base address of the capability, if found. + * @param[in] State Our State + * + * @retval TRUE the capability was found + * @retval FALSE the capability was not found + */ +BOOLEAN +DoesDeviceHaveHtSubtypeCap ( + IN PCI_ADDR DevicePointer, + IN UINT8 CapSubType, + OUT PCI_ADDR *CapabilityBase, + IN STATE_DATA *State + ) +{ + BOOLEAN IsFound; + BOOLEAN IsDone; + PCI_ADDR Reg; + UINT32 Temp; + UINT32 RegSubType; + UINT32 RegSubTypeMask; + + // Set the PCI Config Space base and the match value. + IsFound = FALSE; + IsDone = FALSE; + Reg = DevicePointer; + Reg.Address.Register = 0; + if (CapSubType < (HT_HOST_CAPABILITY + 1)) { + // HT Interface sub type + RegSubType = ((UINT32) (CapSubType << 29) | (UINT32)8); + RegSubTypeMask = HT_INTERFACE_CAP_SUBTYPE_MASK; + } else { + // Other HT capability subtype + RegSubType = ((UINT32) (CapSubType << 27) | (UINT32)8); + RegSubTypeMask = HT_CAP_SUBTYPE_MASK; + } + (*CapabilityBase).AddressValue = (UINT32)ILLEGAL_SBDFO; + + // Find it + do { + LibAmdPciFindNextCap (&Reg, State->ConfigHandle); + if (Reg.AddressValue != (UINT32)ILLEGAL_SBDFO) { + LibAmdPciRead (AccessWidth32, Reg, &Temp, State->ConfigHandle); + // HyperTransport and subtype capability ? + if ((Temp & RegSubTypeMask) == RegSubType) { + *CapabilityBase = Reg; + IsFound = TRUE; + } + // Some other capability, keep looking + } else { + // Not there + IsDone = TRUE; + } + } while (!IsFound && !IsDone); + + return IsFound; +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Retry must be enabled on all coherent links if it is enabled on any coherent links. + * + * @HtFeatMethod{::F_SET_LINK_DATA} + * + * Effectively, this means HT3 on some links cannot be mixed with HT1 on others. + * Scan the CPU to CPU links for this condition and limit those frequencies to HT1 + * if it is detected. + * (Non-coherent links are independent.) + * + * @param[in,out] State global state, port frequency settings. + * + * @retval TRUE Fixup occurred, all coherent links HT1 + * @retval FALSE No changes + */ +BOOLEAN +IsCoherentRetryFixup ( + IN STATE_DATA *State + ) +{ + UINT8 Freq; + UINT8 i; + UINT8 DetectedFrequencyState; + BOOLEAN IsMixed; + UINT32 Temp; + + // + // detectedFrequencyState: + // 0 - initial state + // 1 - HT1 Frequencies detected + // 2 - HT3 Frequencies detected + // + IsMixed = FALSE; + DetectedFrequencyState = 0; + + // Scan coherent links for a mix of HT3 / HT1 + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { + // At this point, Frequency of port [i+1] must equal [i], so just check one of them. + switch (DetectedFrequencyState) { + case 0: + // Set current state to indicate what link frequency we found first + if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) { + // HT3 frequencies + DetectedFrequencyState = 2; + } else { + // HT1 frequencies + DetectedFrequencyState = 1; + } + break; + case 1: + // If HT1 frequency detected, fail any HT3 frequency + if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) { + IsMixed = TRUE; + } + break; + case 2: + // If HT3 frequency detected, fail any HT1 frequency + if ((*State->PortList)[i].SelFrequency <= HT_FREQUENCY_1000M) { + IsMixed = TRUE; + } + break; + default: + ASSERT (FALSE); + } + if (IsMixed) { + // Don't need to keep checking after we find a mix. + break; + } + } + } + + if (IsMixed) { + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { + // Limit coherent links to HT 1 frequencies. + Temp = (*State->PortList)[i].CompositeFrequencyCap & (*State->PortList)[i + 1].CompositeFrequencyCap; + Temp &= HT_FREQUENCY_LIMIT_HT1_ONLY; + ASSERT (Temp != 0); + (*State->PortList)[i].CompositeFrequencyCap = Temp; + (*State->PortList)[i + 1].CompositeFrequencyCap = Temp; + Freq = LibAmdBitScanReverse (Temp); + (*State->PortList)[i].SelFrequency = Freq; + (*State->PortList)[i + 1].SelFrequency = Freq; + } + } + } + return (IsMixed); +} diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatOptimization.h b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatOptimization.h new file mode 100644 index 0000000000..e4cf5099a2 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatOptimization.h @@ -0,0 +1,140 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Link Optimization Feature. + * + * Contains interface for Link Optimization. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $ + * + */ +/* + ***************************************************************************** + * + * Copyright (C) 2012 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. + * + * *************************************************************************** + * + */ + +#ifndef _HT_FEAT_OPTIMIZATION_H_ +#define _HT_FEAT_OPTIMIZATION_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +/** + * Translate a desired width setting to the bits to set in the register field. + */ +UINT8 +ConvertWidthToBits ( + IN UINT8 Value + ); + +/** + * Access HT Link Control Register. + * + */ +VOID +SetHtControlRegisterBits ( + IN PCI_ADDR Reg, + IN UINT8 HiBit, + IN UINT8 LoBit, + IN UINT32 *Value, + IN STATE_DATA *State + ); + +/** + * Get Link features into system data structure. + * + */ +VOID +GatherLinkData ( + IN STATE_DATA *State + ); + +/** + * Optimize Links. + * + */ +VOID +SelectOptimalWidthAndFrequency ( + IN OUT STATE_DATA *State + ); + +/** + * Change the hardware state for all Links according to the now optimized data in the + * port list data structure. + * + */ +VOID +SetLinkData ( + IN STATE_DATA *State + ); + +/** + * Retry must be enabled on all coherent links if it is enabled on any coherent links. + * + */ +BOOLEAN +IsCoherentRetryFixup ( + IN STATE_DATA *State + ); + +/** + * Find a specific HT capability type. + * + * @retval FALSE the capability was not found + */ +BOOLEAN +DoesDeviceHaveHtSubtypeCap ( + IN PCI_ADDR DevicePointer, + IN UINT8 CapSubType, + OUT PCI_ADDR *CapabilityBase, + IN STATE_DATA *State + ); + +#endif /* _HT_FEAT_OPTIMIZATION_H_ */ diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatRouting.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatRouting.c new file mode 100644 index 0000000000..5d34153fc5 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatRouting.c @@ -0,0 +1,493 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Routing Routines + * + * Contains routines for isomorphic topology matching, + * routing determination, and routing initialization. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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 "htGraph.h" +#include "htFeatRouting.h" +#include "htTopologies.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_HT_FEATURES_HTFEATROUTING_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ +typedef struct { + UINT8 **CurrentPosition; + BOOLEAN IsCustomList; +} TOPOLOGY_CONTEXT; + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*************************************************************************** + *** ISOMORPHISM BASED ROUTING TABLE GENERATION CODE *** + ***************************************************************************/ + +/*----------------------------------------------------------------------------------------*/ +/** + * Return the Link on source Node which connects to target Node + * + * @param[in] SourceNode The Node on which to find the Link + * @param[in] TargetNode The Link will connect to this Node + * @param[in] State Our global state + * + * @return the Link to target + */ +UINT8 +STATIC +FindLinkToNode ( + IN UINT8 SourceNode, + IN UINT8 TargetNode, + IN STATE_DATA *State + ) +{ + UINT8 TargetLink; + UINT8 k; + + // A node linked to itself is not a supported topology graph, this is probably an error in the + // topology data. There is not going to be a portlist match for it. + ASSERT (SourceNode != TargetNode); + TargetLink = INVALID_LINK; + for (k = 0; k < State->TotalLinks*2; k += 2) { + if (((*State->PortList)[k].NodeID == SourceNode) && ((*State->PortList)[k + 1].NodeID == TargetNode)) { + TargetLink = (*State->PortList)[k].Link; + break; + } else if (((*State->PortList)[k + 1].NodeID == SourceNode) && ((*State->PortList)[k].NodeID == TargetNode)) { + TargetLink = (*State->PortList)[k + 1].Link; + break; + } + } + ASSERT (TargetLink != INVALID_LINK); + + return TargetLink; +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Is graphA isomorphic to graphB? + * + * If this function returns true, then Perm will contain the permutation + * required to transform graphB into graphA. + * We also use the degree of each Node, that is the number of connections it has, to + * speed up rejection of non-isomorphic graphs (if there is a Node in graphA with n + * connections, there must be at least one unmatched in graphB with n connections). + * + * @param[in] Node the discovered Node which we are trying to match + * with a permutation the topology + * @param[in,out] State our global state, degree and adjacency matrix, + * output a permutation if successful + * @retval TRUE the graphs are isomorphic + * @retval FALSE the graphs are not isomorphic + * + */ +BOOLEAN +STATIC +IsIsomorphic ( + IN UINT8 Node, + IN OUT STATE_DATA *State + ) +{ + UINT8 j; + UINT8 k; + UINT8 Nodecnt; + + // We have only been called if Nodecnt == pSelected->size ! + Nodecnt = State->NodesDiscovered + 1; + + if (Node != Nodecnt) { + // Keep building the permutation + for (j = 0; j < Nodecnt; j++) { + // Make sure the degree matches + if (State->Fabric->SysDegree[Node] != State->Fabric->DbDegree[j]) { + continue; + } + + // Make sure that j hasn't been used yet (ought to use a "used" + // array instead, might be faster) + for (k = 0; k < Node; k++) { + if (State->Fabric->Perm[k] == j) { + break; + } + } + if (k != Node) { + continue; + } + State->Fabric->Perm[Node] = j; + if (IsIsomorphic (Node + 1, State)) { + return TRUE; + } + } + return FALSE; + } else { + // Test to see if the permutation is isomorphic + for (j = 0; j < Nodecnt; j++) { + for (k = 0; k < Nodecnt; k++) { + if (State->Fabric->SysMatrix[j][k] != State->Fabric->DbMatrix[State->Fabric->Perm[j]][State->Fabric->Perm[k]] ) { + return FALSE; + } + } + } + return TRUE; + } +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Set Topology List iterator context to the Beginning and provide the first topology. + * + * Check the interface for a custom topology list. If one is found, set context to the + * first item, and return that item. Otherwise return the first item in the built in list. + * + * @param[in,out] TopologyContextHandle Initialize this context to beginning of lists. + * @param[out] NextTopology The next topology, NULL if end. + * @param[in] State Access to interface, handles. + * + */ +VOID +STATIC +BeginTopologies ( + OUT TOPOLOGY_CONTEXT *TopologyContextHandle, + OUT UINT8 **NextTopology, + IN STATE_DATA *State + ) +{ + if (State->HtBlock->Topolist != NULL) { + // Start with a custom list + TopologyContextHandle->CurrentPosition = State->HtBlock->Topolist; + TopologyContextHandle->IsCustomList = TRUE; + } else { + // Start with the built in list + GetAmdTopolist (&TopologyContextHandle->CurrentPosition); + TopologyContextHandle->IsCustomList = FALSE; + } + *NextTopology = *TopologyContextHandle->CurrentPosition; +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Iterate through available topologies. + * + * Increment to the next list item. If we are doing a custom list, when we reach the end + * switch to the built in list. + * + * @param[in,out] TopologyContextHandle Maintain iterator's context from one call to the next + * @param[out] NextTopology The next topology, NULL if end. + * + */ +VOID +STATIC +GetNextTopology ( + IN OUT TOPOLOGY_CONTEXT *TopologyContextHandle, + OUT UINT8 **NextTopology + ) +{ + // Not valid to continue calling this routine after reaching the end. + ASSERT (TopologyContextHandle->CurrentPosition != NULL); + + if (TopologyContextHandle->IsCustomList) { + // We are iterating the custom list from the interface. + TopologyContextHandle->CurrentPosition++; + if (*TopologyContextHandle->CurrentPosition == NULL) { + // We are at the end of the custom list, switch to the built in list. + TopologyContextHandle->IsCustomList = FALSE; + GetAmdTopolist (&TopologyContextHandle->CurrentPosition); + } + } else { + // We are iterating the built in list + TopologyContextHandle->CurrentPosition++; + // If we are at the end of the built in list, NextTopology == NULL is the AtEnd. + } + *NextTopology = *TopologyContextHandle->CurrentPosition; +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Using the description of the fabric topology we discovered, try to find a match + * among the supported topologies. + * + * @HtFeatMethod{::F_LOOKUP_COMPUTE_AND_LOAD_ROUTING_TABLES} + * + * A supported topology description matches the discovered fabric if the Nodes can be + * matched in such a way that all the Nodes connected in one set are exactly the + * Nodes connected in the other (formally, that the graphs are isomorphic). Which + * Links are used is not really important to matching. If the graphs match, then + * there is a permutation of one that translates the Node positions and Linkages to + * the other. + * + * In order to make the isomorphism test efficient, we test for matched number of Nodes + * (a 4 Node fabric is not isomorphic to a 2 Node topology), and provide degrees of Nodes + * to the isomorphism test. + * + * The generic routing table solution for any topology is predetermined and represented + * as part of the topology. The permutation we computed tells us how to interpret the + * routing onto the fabric we discovered. We do this working backward from the last + * Node discovered to the BSP, writing the routing tables as we go. + * + * @param[in,out] State the discovered fabric, degree matrix, permutation + * + */ +VOID +LookupComputeAndLoadRoutingTables ( + IN OUT STATE_DATA *State + ) +{ + TOPOLOGY_CONTEXT TopologyContextHandle; + UINT8 *Selected; + UINT8 Size; + UINT8 PairCounter; + UINT8 ReqTargetLink; + UINT8 RspTargetLink; + UINT8 ReqTargetNode; + UINT8 RspTargetNode; + UINT8 AbstractBcTargetNodes; + UINT32 BcTargetLinks; + UINT8 NodeCounter; + UINT8 NodeBeingRouted; + UINT8 NodeRoutedTo; + UINT8 BroadcastSourceNode; + + Size = State->NodesDiscovered + 1; + BeginTopologies (&TopologyContextHandle, &Selected, State); + while (Selected != NULL) { + if (GraphHowManyNodes (Selected) == Size) { + // Build Degree vector and Adjacency Matrix for this entry + for (NodeCounter = 0; NodeCounter < Size; NodeCounter++) { + State->Fabric->DbDegree[NodeCounter] = 0; + for (PairCounter = 0; PairCounter < Size; PairCounter++) { + if (GraphIsAdjacent (Selected, NodeCounter, PairCounter)) { + State->Fabric->DbMatrix[NodeCounter][PairCounter] = TRUE; + State->Fabric->DbDegree[NodeCounter]++; + } else { + State->Fabric->DbMatrix[NodeCounter][PairCounter] = FALSE; + } + } + } + + if (IsIsomorphic (0, State)) { + break; // A matching topology was found + } + } + GetNextTopology (&TopologyContextHandle, &Selected); + } + + if (Selected != NULL) { + // Compute the reverse Permutation + for (NodeCounter = 0; NodeCounter < Size; NodeCounter++) { + State->Fabric->ReversePerm[State->Fabric->Perm[NodeCounter]] = NodeCounter; + } + + // Start with the last discovered Node, and move towards the BSP + for (NodeCounter = 0; NodeCounter < Size; NodeCounter++) { + NodeBeingRouted = ((Size - 1) - NodeCounter); + for (NodeRoutedTo = 0; NodeRoutedTo < Size; NodeRoutedTo++) { + BcTargetLinks = 0; + AbstractBcTargetNodes = GraphGetBc (Selected, State->Fabric->Perm[NodeBeingRouted], State->Fabric->Perm[NodeRoutedTo]); + + for (BroadcastSourceNode = 0; BroadcastSourceNode < MAX_NODES; BroadcastSourceNode++) { + if ((AbstractBcTargetNodes & ((UINT32)1 << BroadcastSourceNode)) != 0) { + // Accepting broadcast from yourself is handled in Nb, so in the topology graph it is an error. + ASSERT (NodeBeingRouted != State->Fabric->ReversePerm[BroadcastSourceNode]); + BcTargetLinks |= (UINT32)1 << FindLinkToNode (NodeBeingRouted, State->Fabric->ReversePerm[BroadcastSourceNode], State); + } + } + + if (NodeBeingRouted == NodeRoutedTo) { + ReqTargetLink = ROUTE_TO_SELF; + RspTargetLink = ROUTE_TO_SELF; + } else { + ReqTargetNode = GraphGetReq (Selected, State->Fabric->Perm[NodeBeingRouted], State->Fabric->Perm[NodeRoutedTo]); + ReqTargetLink = FindLinkToNode (NodeBeingRouted, State->Fabric->ReversePerm[ReqTargetNode], State); + + RspTargetNode = GraphGetRsp (Selected, State->Fabric->Perm[NodeBeingRouted], State->Fabric->Perm[NodeRoutedTo]); + RspTargetLink = FindLinkToNode (NodeBeingRouted, State->Fabric->ReversePerm[RspTargetNode], State); + } + State->Nb->WriteFullRoutingTable (NodeBeingRouted, NodeRoutedTo, ReqTargetLink, RspTargetLink, BcTargetLinks, State->Nb); + } + // Clean up discovery 'footprint' that otherwise remains in the routing table. It didn't hurt + // anything, but might cause confusion during debug and validation. Do this by setting the + // route back to all self routes. Since it's the Node that would be one more than actually installed, + // this only applies if less than MaxNodes were found. + // + if (Size < MAX_NODES) { + State->Nb->WriteFullRoutingTable (NodeBeingRouted, Size, ROUTE_TO_SELF, ROUTE_TO_SELF, 0, State->Nb); + } + } + } else { + // + // No Matching Topology was found + // Error Strategy: + // Auto recovery doesn't seem likely, Force boot as 1P. + // For reporting, logging, provide number of Nodes + // If not implemented or returns, boot as BSP uniprocessor. + // + // This can be caused by not supplying an additional topology list, if your board is not one of the built-in topologies. + // + NotifyErrorCohNoTopology (State->NodesDiscovered, State); + IDS_ERROR_TRAP; + // Force 1P + State->NodesDiscovered = 0; + State->TotalLinks = 0; + State->Nb->EnableRoutingTables (0, State->Nb); + State->HtInterface->CleanMapsAfterError (State); + } + // Save the topology pointer, or NULL, for other features + State->Fabric->MatchedTopology = Selected; + IDS_HDT_CONSOLE ( + HT_TRACE, + "System routed as %s.\n", + ((TopologyContextHandle.IsCustomList) ? + "custom topology" : + (((Selected == amdHtTopologySingleNode) || (Selected == NULL)) ? + "single node" : + ((Selected == amdHtTopologyDualNode) ? + "dual node" : + ((Selected == amdHtTopologyFourSquare) ? + "four node box" : + ((Selected == amdHtTopologyFourKite) ? + "four node kite" : + ((Selected == amdHtTopologyFourFully) ? + "fully connected four-way" : + ((Selected == amdHtTopologyEightDoubloon) ? + "MCM max performance" : + ((Selected == amdHtTopologyEightTwinFullyFourWays) ? + "MCM max I/O" : + "AMD builtin topology")))))))) + ); +} + +/*----------------------------------------------------------------------------------------*/ +/** + * Make a Hop Count Table for the installed topology. + * + * @HtFeatMethod{::F_MAKE_HOP_COUNT_TABLE} + * + * For SLIT, create a node x node matrix with the number of hops. We can do this + * using the topology and the permutation, counting the nodes visited in the routes between + * nodes. + * + * @param[in,out] State access topology, permutation, update hop table + * + */ +VOID +MakeHopCountTable ( + IN OUT STATE_DATA *State + ) +{ + UINT8 Origin; + UINT8 Target; + UINT8 Current; + UINT8 Hops; + UINT8 Size; + + ASSERT (State->Fabric != NULL); + if (State->HopCountTable != NULL) { + if (State->Fabric->MatchedTopology != NULL) { + Size = GraphHowManyNodes (State->Fabric->MatchedTopology); + State->HopCountTable->Size = Size; + // + // For each node, targeting each node, follow the request path through the database graph, + // counting the number of edges. + // + for (Origin = 0; Origin < Size; Origin++) { + for (Target = 0; Target < Size; Target++) { + // If both nodes are the same the answer will be zero + Hops = 0; + // Current starts as the database node corresponding to system node Origin. + Current = State->Fabric->Perm[Origin]; + // Stop if Current is the database node corresponding to system node Target + while (Current != State->Fabric->Perm[Target]) { + // This is a hop, so count it. Move Current to the next intermediate database node. + Hops++; + Current = GraphGetReq (State->Fabric->MatchedTopology, Current, State->Fabric->Perm[Target]); + } + // Put the hop count in the table. + State->HopCountTable->Hops[ ((Origin * Size) + Target)] = Hops; + } + } + } + } +} diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatRouting.h b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatRouting.h new file mode 100644 index 0000000000..f672cc4c83 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatRouting.h @@ -0,0 +1,90 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Routing Feature Interface. + * + * Interfaces to routing and isomorphism routines. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $ + * + */ +/* + ***************************************************************************** + * + * Copyright (C) 2012 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. + * + * *************************************************************************** + * + */ + +#ifndef _HT_FEAT_ROUTING_H_ +#define _HT_FEAT_ROUTING_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +/** + * Using the description of the fabric topology we discovered, try to find a match + * among the supported topologies. + * + */ +VOID +LookupComputeAndLoadRoutingTables ( + IN OUT STATE_DATA *State + ); + +/** + * Make a Hop Count Table for the installed topology. + * + */ +VOID +MakeHopCountTable ( + IN OUT STATE_DATA *State + ); + +#endif /* _HT_FEAT_ROUTING_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSets.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSets.c new file mode 100644 index 0000000000..112dc486a3 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSets.c @@ -0,0 +1,135 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * HyperTransport feature sets initializers. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* + ***************************************************************************** + * + * Copyright (C) 2012 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 "amdlib.h" +#include "OptionsHt.h" +#include "Ids.h" +#include "Topology.h" +#include "htFeat.h" +#include "CommonReturns.h" +#include "htFeatDynamicDiscovery.h" +#include "htFeatRouting.h" +#include "htFeatNoncoherent.h" +#include "htFeatOptimization.h" +#include "htFeatGanging.h" +#include "htFeatSublinks.h" +#include "htFeatTrafficDistribution.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_HT_FEATURES_HTFEATSETS_FILECODE +extern CONST OPTION_HT_CONFIGURATION OptionHtConfiguration; + +/** + * Initializer for the default feature set implementation, + * full features. + */ +CONST HT_FEATURES ROMDATA HtFeaturesDefault = +{ + CoherentDiscovery, + LookupComputeAndLoadRoutingTables, + MakeHopCountTable, + ProcessLink, + GatherLinkData, + SelectOptimalWidthAndFrequency, + RegangLinks, + SubLinkRatioFixup, + IsCoherentRetryFixup, + SetLinkData, + TrafficDistribution, + SetHtControlRegisterBits, + ConvertWidthToBits +}; + +/** +* Initializer for the coherent HT feature set implementation +* (IO is using PCIe). +*/ +CONST HT_FEATURES ROMDATA HtFeaturesCoherentOnly = +{ + CoherentDiscovery, + LookupComputeAndLoadRoutingTables, + MakeHopCountTable, + (PF_PROCESS_LINK)CommonVoid, + GatherLinkData, + SelectOptimalWidthAndFrequency, + RegangLinks, + SubLinkRatioFixup, + IsCoherentRetryFixup, + SetLinkData, + TrafficDistribution, + SetHtControlRegisterBits, + ConvertWidthToBits +}; + +/** + * Initializer for the non-coherent only build option. + */ +CONST HT_FEATURES ROMDATA HtFeaturesNonCoherentOnly = +{ + (PF_COHERENT_DISCOVERY)CommonVoid, + (PF_LOOKUP_COMPUTE_AND_LOAD_ROUTING_TABLES)CommonVoid, + (PF_MAKE_HOP_COUNT_TABLE)CommonVoid, + ProcessLink, + GatherLinkData, + SelectOptimalWidthAndFrequency, + (PF_REGANG_LINKS)CommonVoid, + (PF_SUBLINK_RATIO_FIXUP)CommonVoid, + (PF_IS_COHERENT_RETRY_FIXUP)CommonReturnFalse, + SetLinkData, + (PF_TRAFFIC_DISTRIBUTION)CommonVoid, + SetHtControlRegisterBits, + ConvertWidthToBits +}; diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSublinks.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSublinks.c new file mode 100644 index 0000000000..194861a055 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSublinks.c @@ -0,0 +1,232 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * SubLink management Routines. + * + * Contains routines for subLink frequency ratios. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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 "amdlib.h" +#include "Topology.h" +#include "htFeat.h" +#include "IdsHt.h" +#include "htFeatSublinks.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_HT_FEATURES_HTFEATSUBLINKS_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +typedef struct { + UINT8 HiFreq; + UINT8 LoFreq; +} VALID_RATIO_ITEM; + +STATIC CONST VALID_RATIO_ITEM ROMDATA ValidRatioList[] = +{ + {HT_FREQUENCY_3200M, HT_FREQUENCY_1600M}, // 3200MHz / 1600MHz 2:1 + {HT_FREQUENCY_3200M, HT_FREQUENCY_800M}, // 3200MHz / 800MHz 4:1 + {HT_FREQUENCY_3200M, HT_FREQUENCY_400M}, // 3200MHz / 400MHz 8:1 + {HT_FREQUENCY_2800M, HT_FREQUENCY_1400M}, // 2800MHz / 1400MHz 2:1 + {HT_FREQUENCY_2400M, HT_FREQUENCY_1200M}, // 2400MHz / 1200MHz 2:1 + {HT_FREQUENCY_2400M, HT_FREQUENCY_600M}, // 2400MHz / 600MHz 4:1 + {HT_FREQUENCY_2400M, HT_FREQUENCY_400M}, // 2400MHz / 400MHz 6:1 + {HT_FREQUENCY_2000M, HT_FREQUENCY_1000M}, // 2000MHz / 1000MHz 2:1 + {HT_FREQUENCY_1600M, HT_FREQUENCY_800M}, // 1600MHz / 800MHz 2:1 + {HT_FREQUENCY_1600M, HT_FREQUENCY_400M}, // 1600MHz / 400MHz 4:1 + {HT_FREQUENCY_1600M, HT_FREQUENCY_200M}, // 1600MHz / 200Mhz 8:1 + {HT_FREQUENCY_1200M, HT_FREQUENCY_600M}, // 1200MHz / 600MHz 2:1 + {HT_FREQUENCY_1200M, HT_FREQUENCY_200M}, // 1200MHz / 200MHz 6:1 + {HT_FREQUENCY_800M, HT_FREQUENCY_400M}, // 800MHz / 400MHz 2:1 + {HT_FREQUENCY_800M, HT_FREQUENCY_200M}, // 800MHz / 200MHz 4:1 + {HT_FREQUENCY_400M, HT_FREQUENCY_200M} // 400MHz / 200MHz 2:1 +}; + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*************************************************************************** + *** Link Optimization *** + ***************************************************************************/ + +/*----------------------------------------------------------------------------------------*/ +/** + * Iterate through all Links, checking the frequency of each subLink pair. + * + * @HtFeatMethod{::F_SUBLINK_RATIO_FIXUP} + * + * Make the adjustment to the port list data so that the frequencies + * are at a valid ratio, reducing frequency as needed to achieve + * this. (All Links support the minimum 200 MHz frequency.) Repeat + * the above until no adjustments are needed. + * @note no hardware state changes in this routine. + * + * @param[in,out] State Link state and port list + * + */ +VOID +SubLinkRatioFixup ( + IN OUT STATE_DATA *State + ) +{ + UINT8 i; + UINT8 j; + UINT8 ValidRatioItem; + BOOLEAN Changes; + BOOLEAN Downgrade; + UINT8 HiIndex; + UINT8 HiFreq; + UINT8 LoFreq; + + UINT32 Temp; + + do { + Changes = FALSE; + for (i = 0; i < State->TotalLinks*2; i++) { + // Must be a CPU Link + if ((*State->PortList)[i].Type != PORTLIST_TYPE_CPU) { + continue; + } + // Only look for subLink1's + if ((*State->PortList)[i].Link < 4) { + continue; + } + + for (j = 0; j < State->TotalLinks*2; j++) { + // Step 1. Find the matching subLink0 + if ((*State->PortList)[j].Type != PORTLIST_TYPE_CPU) { + continue; + } + if ((*State->PortList)[j].NodeID != (*State->PortList)[i].NodeID) { + continue; + } + if ((*State->PortList)[j].Link != ((*State->PortList)[i].Link & 0x03)) { + continue; + } + + // Step 2. Check for an illegal frequency ratio + if ((*State->PortList)[i].SelFrequency >= (*State->PortList)[j].SelFrequency) { + HiIndex = i; + HiFreq = (*State->PortList)[i].SelFrequency; + LoFreq = (*State->PortList)[j].SelFrequency; + } else { + HiIndex = j; + HiFreq = (*State->PortList)[j].SelFrequency; + LoFreq = (*State->PortList)[i].SelFrequency; + } + + // The frequencies are 1:1, no need to do anything + if (HiFreq == LoFreq) { + break; + } + + Downgrade = TRUE; + + for (ValidRatioItem = 0; ValidRatioItem < (sizeof (ValidRatioList) / sizeof (VALID_RATIO_ITEM)); ValidRatioItem++) { + if ((HiFreq == ValidRatioList[ValidRatioItem].HiFreq) && + (LoFreq == ValidRatioList[ValidRatioItem].LoFreq)) { + Downgrade = FALSE; + break; + } + } + + // Step 3. Downgrade the higher of the two frequencies, and set Changes to FALSE + if (Downgrade) { + // Although the problem was with the port specified by hiIndex, we need to + // Downgrade both ends of the Link. + HiIndex = HiIndex & 0xFE; // Select the 'upstream' (i.e. even) port + + Temp = (*State->PortList)[HiIndex].CompositeFrequencyCap; + + // Remove HiFreq from the list of valid frequencies + Temp = Temp & ~((UINT32)1 << HiFreq); + ASSERT (Temp != 0); + (*State->PortList)[HiIndex].CompositeFrequencyCap = (UINT32)Temp; + (*State->PortList)[HiIndex + 1].CompositeFrequencyCap = (UINT32)Temp; + + HiFreq = LibAmdBitScanReverse (Temp); + + (*State->PortList)[HiIndex].SelFrequency = HiFreq; + (*State->PortList)[HiIndex + 1].SelFrequency = HiFreq; + + Changes = TRUE; + } + } + } + } while (Changes); // Repeat until a valid configuration is reached +} diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSublinks.h b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSublinks.h new file mode 100644 index 0000000000..d8c1d9d00b --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatSublinks.h @@ -0,0 +1,80 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * SubLink Interface. + * + * Contains interface to subLink management feature, for unganged subLinks. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $ + * + */ +/* + ***************************************************************************** + * + * Copyright (C) 2012 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. + * + * *************************************************************************** + * + */ + +#ifndef _HT_FEAT_SUBLINKS_H_ +#define _HT_FEAT_SUBLINKS_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +/** + * Iterate through all Links, checking the frequency of each subLink pair. + * + */ +VOID +SubLinkRatioFixup ( + IN OUT STATE_DATA *State + ); + +#endif /* _HT_FEAT_SUBLINKS_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.c new file mode 100644 index 0000000000..5e9fe0e7ba --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.c @@ -0,0 +1,420 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Traffic Distribution Routines. + * + * Contains routines for traffic distribution + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* + ***************************************************************************** + * + * Copyright (C) 2012 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 "amdlib.h" +#include "Ids.h" +#include "Topology.h" +#include "htFeat.h" +#include "htInterface.h" +#include "htNb.h" +#include "htNotify.h" +#include "htFeatTrafficDistribution.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_HT_FEATURES_HTFEATTRAFFICDISTRIBUTION_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ +/// Enum for the possible link connection status +typedef enum { + Unconnected = 0, ///< Nodes have not connected link. + UngangedLink, ///< Nodes are connected with one unganged link. + Redundant, ///< Nodes are connected with multi-unganged link. + GangedLink, ///< Nodes are connected with one or mutiple ganged link. + MaxLink ///< Max links status. +} LINK_STATUS; + +/// Local port connection state data structure +typedef struct { + LINK_STATUS ConnectionState; /**< The link connection state. */ + UINT8 BigLinkPort; /**< The Port number for ganged Link */ +} PORT_CONNECTION_STATE; + +/// Local ganged link for Victim Distribution data structure +typedef struct { +UINT8 NodeA; ///< Source Node from Node A To Node B and DstNode from Node A To Node B. +UINT8 NodeB; ///< Source Node from Node B To Node A and DstNode from Node A To Node B. +UINT8 VictimedLinkFromNodeAToNodeB; ///< Victimed Link from Node A To Node B. +UINT8 VictimedLinkFromNodeBToNodeA; ///< Victimed Link from Node B To Node A. +} VICTIM_ROUTED_LINK; + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------------------*/ +/** + * Identify Links which can have traffic distribution. + * + * @HtFeatMethod{::F_TRAFFIC_DISTRIBUTION} + * + * If there are redundant links between any nodes, traffic distribution allows the + * redundant links to be used to improve performance. + * + * There are three types of traffic distribution. Their use is mutually exclusive, all + * can not be used at once. + * + * Coherent Traffic Distribution is for systems of exactly two nodes only. All links must + * be symmetrical (the same width). As many links as are connected can be distributed over. + * + * Victim Distribution is a way to direct victim traffic on to ganged links and away from unganged links + * as a way to reduce unganged link congestion for a system only if 2 processor (4 node) G34 system. + * A node can enables victim distribution mode only if the node connects to another node directly with + * only 1 unganged link hop and indirectly through 2 ganged link hops. + * + * Link Pair Traffic Distribution works with redundant pairs of links between any two nodes, + * it does not matter how many nodes are in the system or how many have a redundant link pair. + * A node can have redundant link pairs with more than one other node. + * The link pair can be asymmetric, the largest link must be used as the master. However, + * between any pair of nodes there is only one pair of redundant links, and there is a limit + * to the total number of pairs each node can have. So not all links will necessarily be + * made usable. + * + * @param[in] State port list data + */ +VOID +TrafficDistribution ( + IN STATE_DATA *State + ) +{ + UINT32 Links01; + UINT32 Links10; + UINT32 LinksAB; + UINT32 LinksBA; + UINT8 LinkCount; + UINT8 UngandLinkCount; + UINT8 VictimedRouteCount; + UINT8 i; + UINT8 LastLink; + BOOLEAN IsAsymmetric; + BOOLEAN IsVictimedRouteFound; + UINT8 RedundantLinkCount[MAX_NODES][MAX_NODES]; + UINT8 MasterLinkPort[MAX_NODES][MAX_NODES]; + UINT8 AlternateLinkPort[MAX_NODES][MAX_NODES]; + UINT8 NodeA; + UINT8 NodeB; + UINT8 PairCount; + VICTIM_ROUTED_LINK VictimRoutedLink[MAX_NODES]; + PORT_CONNECTION_STATE GangedLinkPort[MAX_NODES][MAX_NODES]; + + LastLink = 0xFF; + IsAsymmetric = FALSE; + + // Traffic Distribution is only used when there are exactly two Nodes in the system + // and when all the links are symmetric, same width. + if ((State->NodesDiscovered + 1) == 2) { + Links01 = 0; + Links10 = 0; + LinkCount = 0; + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && + ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { + if ((LastLink != 0xFF) && + ((*State->PortList)[i].SelWidthOut != (*State->PortList)[LastLink].SelWidthOut) && + ((*State->PortList)[i + 1].SelWidthOut != (*State->PortList)[LastLink + 1].SelWidthOut)) { + IsAsymmetric = TRUE; + break; + } + Links01 |= (UINT32)1 << (*State->PortList)[i].Link; + Links10 |= (UINT32)1 << (*State->PortList)[i + 1].Link; + LinkCount++; + LastLink = i; + } + } + ASSERT (LinkCount != 0); + // Don't setup Traffic Distribution if only one Link is being used or there were asymmetric widths + if ((LinkCount != 1) && !IsAsymmetric) { + IDS_HDT_CONSOLE (HT_TRACE, "Applying coherent traffic distribution.\n"); + State->Nb->WriteTrafficDistribution (Links01, Links10, State->Nb); + // If we did Traffic Distribution, we must not do Link Pair, so get out of here. + return; + } + } + + // Victim Distribution is only used when there are exactly two processor (4 node) system + // and the node connects to another node directly with only 1 unganged link hop and indirectly + // through 2 ganged link hops. + if ((State->NodesDiscovered + 1) == 4) { + UngandLinkCount = 0; + + // Initialize the ganged link state data structures + for (NodeA = 0; NodeA < MAX_NODES; NodeA++) { + for (NodeB = 0; NodeB < MAX_NODES; NodeB++) { + GangedLinkPort[NodeA][NodeB].ConnectionState = 0; + GangedLinkPort[NodeA][NodeB].BigLinkPort = 0; + } + } + + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && + ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { + NodeA = (*State->PortList)[i].NodeID; + NodeB = (*State->PortList)[i + 1].NodeID; + if ((((*State->PortList)[i].SelRegang == TRUE) && + ((*State->PortList)[i].PrvWidthOutCap == HT_WIDTH_16_BITS)) || + ((*State->PortList)[i].SelWidthOut == HT_WIDTH_16_BITS)) { + if (GangedLinkPort[NodeA][NodeB].ConnectionState <= Redundant) { + // Record it if it is the first ganged link connecting two nodes. + GangedLinkPort[NodeA][NodeB].BigLinkPort = (*State->PortList)[i].Link; + GangedLinkPort[NodeB][NodeA].BigLinkPort = (*State->PortList)[i + 1].Link; + GangedLinkPort[NodeA][NodeB].ConnectionState = GangedLink; + GangedLinkPort[NodeB][NodeA].ConnectionState = GangedLink; + } + } else { + if (GangedLinkPort[NodeA][NodeB].ConnectionState == Unconnected) { + // Save it if it is firstly unganged link and also does no exist ganged link between node A and node B. + GangedLinkPort[NodeA][NodeB].ConnectionState = UngangedLink; + GangedLinkPort[NodeB][NodeA].ConnectionState = UngangedLink; + + UngandLinkCount++; + } else if (GangedLinkPort[NodeA][NodeB].ConnectionState == UngangedLink) { + // Ignore it if there are multi-unganged links between node A and node B. + GangedLinkPort[NodeA][NodeB].ConnectionState = Redundant; + GangedLinkPort[NodeB][NodeA].ConnectionState = Redundant; + + // Adjust the count because had it recorded once. + UngandLinkCount--; + } + } + } + } + + if (UngandLinkCount != 0) { + VictimedRouteCount = 0; + + // Check Link by Link if one unganged link can direct victim traffic on to indirectly 2 ganged link hops + for (NodeA = 0; NodeA <= (State->NodesDiscovered); NodeA++) { + for (NodeB = NodeA +1; NodeB <= (State->NodesDiscovered); NodeB++) { + if (GangedLinkPort[NodeA][NodeB].ConnectionState == UngangedLink) { + // This is unganged link connecting two nodes + IsVictimedRouteFound = FALSE; + + for (i = 0; i <= (State->NodesDiscovered); i++) { + if ((i != NodeA) && (i != NodeB) && (GangedLinkPort[NodeA][i].ConnectionState == GangedLink)) { + // This is the first ganged link hop to Destined Node + VictimRoutedLink[VictimedRouteCount].NodeA = NodeA; + VictimRoutedLink[VictimedRouteCount].VictimedLinkFromNodeAToNodeB = GangedLinkPort[NodeA][i].BigLinkPort; + if (GangedLinkPort[i][NodeB].ConnectionState == GangedLink) { + // This is the second ganged link hop to Destined Node + // Save the Destined Node and the Reversed Destination Link + VictimRoutedLink[VictimedRouteCount].NodeB = NodeB; + VictimRoutedLink[VictimedRouteCount].VictimedLinkFromNodeBToNodeA = GangedLinkPort[NodeB][i].BigLinkPort; + if (!IsVictimedRouteFound) { + VictimedRouteCount++; + + // This is first victimed route where there are indirectly 2 ganged link hops to Destined Node + IsVictimedRouteFound = TRUE; + } else { + // This is second victimed route, so we need to replace to the new Reversed Destination Link + VictimRoutedLink[VictimedRouteCount - 1].VictimedLinkFromNodeBToNodeA = GangedLinkPort[NodeB][i].BigLinkPort; + } + } + } + } + } + } + } + + // Setup Victim Distribution Mode + if (VictimedRouteCount != 0) { + IDS_HDT_CONSOLE (HT_TRACE, "Applying coherent Victim distribution.\n"); + LinksAB = 0; + LinksBA = 0; + for (i = 0; i < VictimedRouteCount; i++) { + LinksAB = (UINT32)1 << VictimRoutedLink[i].VictimedLinkFromNodeAToNodeB; + LinksBA = (UINT32)1 << VictimRoutedLink[i].VictimedLinkFromNodeBToNodeA; + State->Nb->WriteVictimDistribution ( + VictimRoutedLink[i].NodeA, + VictimRoutedLink[i].NodeB, + LinksAB, + LinksBA, + State->Nb + ); + } + // If we did Victim Distribution, we must not do Link Pair when there are more than two nodes, so exit here. + return; + } + } + } + + // Either there are more than two nodes, Asymmetric links, or no redundant links. + // See if we can use Link Pair Traffic Distribution + LibAmdMemFill (&RedundantLinkCount, 0, (MAX_NODES * MAX_NODES), State->ConfigHandle); + for (i = 0; i < (State->TotalLinks * 2); i += 2) { + if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && + ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { + NodeA = (*State->PortList)[i].NodeID; + NodeB = (*State->PortList)[i + 1].NodeID; + if (RedundantLinkCount[NodeA][NodeB] == 0) { + // This is the first link connecting two nodes + ASSERT (RedundantLinkCount[NodeB][NodeA] == 0); + MasterLinkPort[NodeA][NodeB] = i; + MasterLinkPort[NodeB][NodeA] = i + 1; + } else { + // This is a redundant link. If it is larger than the current master link, + // make it the new master link. + // + if (((*State->PortList)[MasterLinkPort[NodeA][NodeB]].SelWidthOut < (*State->PortList)[i].SelWidthOut) && + ((*State->PortList)[MasterLinkPort[NodeB][NodeA]].SelWidthOut < (*State->PortList)[i + 1].SelWidthOut)) { + // Make the old master link the alternate, we don't need to check, it is bigger. + AlternateLinkPort[NodeA][NodeB] = MasterLinkPort[NodeA][NodeB]; + AlternateLinkPort[NodeB][NodeA] = MasterLinkPort[NodeB][NodeA]; + MasterLinkPort[NodeA][NodeB] = i; + MasterLinkPort[NodeB][NodeA] = i + 1; + } else { + // Since the new link isn't bigger than the Master, check if it is bigger than the alternate, + // if we have an alternate. If we don't have an alternate yet, make this link the alternate. + if (RedundantLinkCount[NodeA][NodeB] == 1) { + AlternateLinkPort[NodeA][NodeB] = i; + AlternateLinkPort[NodeB][NodeA] = i + 1; + } else { + if (((*State->PortList)[AlternateLinkPort[NodeA][NodeB]].SelWidthOut < (*State->PortList)[i].SelWidthOut) && + ((*State->PortList)[AlternateLinkPort[NodeB][NodeA]].SelWidthOut < (*State->PortList)[i + 1].SelWidthOut)) { + // Warning: the alternate link is an unusable redundant link + // Then make the new link the alternate link. + NotifyWarningOptUnusedLinks ( + NodeA, + (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].Link, + NodeB, + (*State->PortList)[AlternateLinkPort[NodeB][NodeA]].Link, + State + ); + ASSERT (RedundantLinkCount[NodeB][NodeA] > 1); + AlternateLinkPort[NodeA][NodeB] = i; + AlternateLinkPort[NodeB][NodeA] = i + 1; + } else { + // Warning the current link is an unusable redundant link + NotifyWarningOptUnusedLinks (NodeA, (*State->PortList)[i].Link, NodeB, (*State->PortList)[i].Link, State); + } + } + } + } + RedundantLinkCount[NodeA][NodeB]++; + RedundantLinkCount[NodeB][NodeA]++; + } + } + // If we found any, now apply up to 4 per node + for (NodeA = 0; NodeA < MAX_NODES; NodeA++) { + PairCount = 0; + for (NodeB = 0; NodeB < MAX_NODES; NodeB++) { + if (RedundantLinkCount[NodeA][NodeB] > 1) { + // Then there is a pair of links (at least, but we only care about the pair not the extras) + if (PairCount < MAX_LINK_PAIRS) { + // Program it + if ((*State->PortList)[MasterLinkPort[NodeA][NodeB]].SelWidthOut + != (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].SelWidthOut) { + IsAsymmetric = TRUE; + } else { + IsAsymmetric = FALSE; + } + State->Nb->WriteLinkPairDistribution ( + NodeA, + NodeB, + PairCount, + IsAsymmetric, + (*State->PortList)[MasterLinkPort[NodeA][NodeB]].Link, + (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].Link, + State->Nb + ); + PairCount++; + } else { + // Warning: More link pairs than can be distributed + NotifyWarningOptLinkPairExceed ( + NodeA, NodeB, + (*State->PortList)[MasterLinkPort[NodeA][NodeB]].Link, + (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].Link, + State); + // Disable the link pair from the other node, the analysis loop made sure there + // can only be a single link pair between a pair of nodes. + RedundantLinkCount[NodeB][NodeA] = 1; + } + } + } + IDS_HDT_CONSOLE ( + HT_TRACE, + ((PairCount != 0) ? + "Node %d applying %d link pair distributions.\n" : + ""), + NodeA, + PairCount + ); + } +} + diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.h b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.h new file mode 100644 index 0000000000..8fda546892 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.h @@ -0,0 +1,79 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Traffic Distribution Interface. + * + * Interface to traffic distribution feature. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $ + * + */ +/* +***************************************************************************** +* +* Copyright (C) 2012 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. +* +* *************************************************************************** +* +*/ + +#ifndef _HT_FEAT_TRAFFIC_DISTRIBUTION_H_ +#define _H_TFEAT_TRAFFIC_DISTRIBUTION_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ +/** + * Identify Links which can have traffic distribution. + * + */ +VOID +TrafficDistribution ( + IN STATE_DATA *State + ); + +#endif /* _HT_FEAT_TRAFFIC_DISTRIBUTION_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htIds.c b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htIds.c new file mode 100644 index 0000000000..05028dbcc3 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htIds.c @@ -0,0 +1,150 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * AMD IDS HyperTransport Implementation. + * + * Contains AMD AGESA Integrated Debug HT related support. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: HyperTransport + * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $ + */ +/***************************************************************************** + * + * Copyright (C) 2012 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. + * + * + ***************************************************************************/ + + +#include "AGESA.h" +#include "amdlib.h" +#include "Ids.h" +#include "Topology.h" +#include "htFeat.h" +#include "IdsHt.h" +#include "htInterface.h" +#include "htInterfaceGeneral.h" +#include "htNb.h" +#include "heapManager.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) +#define FILECODE PROC_HT_FEATURES_HTIDS_FILECODE + + +/*-------------------------------------------------------------------------------------*/ +/** + * Apply an IDS port override to the desired HT link. + * + * The IDS port override allows absolute control of a link's frequency and width, such as + * would be used for board characterization and test. The IDS backend code is responsible + * for handling the NV items and building them into a port override list. Here we search + * that list for any overrides which apply, and update the data used by the HT feature code. + * + * @param[in] IsSourcePort Since we handle both ports on a match, only do that if TRUE. + * @param[in,out] Port0 The PORTLIST item for the first endpoint of a link. + * @param[in,out] Port1 The PORTLIST item for the second endpoint of a link. + * @param[in,out] PortOverrideList IN: A pointer to the port override list or NULL, + * OUT: A pointer to the port override list. + * @param[in] State access to ht interface and nb support methods. + * + */ +VOID +HtIdsGetPortOverride ( + IN BOOLEAN IsSourcePort, + IN OUT PORT_DESCRIPTOR *Port0, + IN OUT PORT_DESCRIPTOR *Port1, + IN OUT HTIDS_PORT_OVERRIDE_LIST *PortOverrideList, + IN STATE_DATA *State + ) +{ + LOCATE_HEAP_PTR LocHeapParams; + UINT8 SocketA; + UINT8 SocketB; + UINT8 PackageLinkA; + UINT8 PackageLinkB; + HTIDS_PORT_OVERRIDE_LIST p; + + if (IsSourcePort) { + ASSERT (PortOverrideList != NULL); + // The caller can cache the override list by providing the pointer (to the heap buffer). + // If the pointer to the port override list is null, then check if it is on the heap, + // and update the caller's pointer so it is cached. + // If the buffer is not in heap, call the IDS backend to get the NV data (which is likely also + // in heap). + if (*PortOverrideList == NULL) { + // locate the table in heap + LocHeapParams.BufferHandle = IDS_HT_DATA_HANDLE; + if (HeapLocateBuffer (&LocHeapParams, State->ConfigHandle) == AGESA_SUCCESS) { + *PortOverrideList = (HTIDS_PORT_OVERRIDE_LIST)LocHeapParams.BufferPtr; + } else { + // Ask IDS backend code for the list + IDS_OPTION_HOOK (IDS_HT_CONTROL, PortOverrideList, State->ConfigHandle); + } + } + ASSERT (*PortOverrideList != NULL); + + // Search the port override list to see if there is an override that applies to this link. + // The match criteria are if either endpoint of the current port list item matches + // port override. + p = *PortOverrideList; + SocketA = State->HtInterface->GetSocketFromMap (Port0->NodeID, State); + PackageLinkA = State->Nb->GetPackageLink (Port0->NodeID, Port0->Link, State->Nb); + SocketB = State->HtInterface->GetSocketFromMap (Port1->NodeID, State); + PackageLinkB = State->Nb->GetPackageLink (Port1->NodeID, Port1->Link, State->Nb); + + while ((p != NULL) && (p->Socket != HT_LIST_TERMINAL)) { + if ((((p->Socket == SocketA) || (p->Socket == HT_LIST_MATCH_ANY)) && + ((p->Link == PackageLinkA) || ((p->Link == HT_LIST_MATCH_ANY) && + (!IsPackageLinkInternal (PackageLinkA))) || ((p->Link == HT_LIST_MATCH_INTERNAL_LINK) && (IsPackageLinkInternal (PackageLinkA))))) || + (((p->Socket == SocketB) || (p->Socket == HT_LIST_MATCH_ANY)) && + ((p->Link == PackageLinkB) || ((p->Link == HT_LIST_MATCH_ANY) && + (!IsPackageLinkInternal (PackageLinkA))) || ((p->Link == HT_LIST_MATCH_INTERNAL_LINK) && (IsPackageLinkInternal (PackageLinkB)))))) + { + // Found a match, update width and frequency of both endpoints. + if (p->WidthIn != HT_LIST_TERMINAL) { + Port0->SelWidthIn = p->WidthIn; + Port1->SelWidthOut = p->WidthIn; + } + if (p->WidthOut != HT_LIST_TERMINAL) { + Port0->SelWidthOut = p->WidthOut; + Port1->SelWidthIn = p->WidthOut; + } + if (p->Frequency != HT_LIST_TERMINAL) { + Port0->SelFrequency = p->Frequency; + Port1->SelFrequency = p->Frequency; + } + break; + } else { + p++; + } + } + } +} + |