diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.c')
-rw-r--r-- | src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.c | 420 |
1 files changed, 420 insertions, 0 deletions
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 + ); + } +} + |