aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f15/Proc/HT/Features/htFeatTrafficDistribution.c
diff options
context:
space:
mode:
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.c420
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
+ );
+ }
+}
+