AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / Features / htFeatTrafficDistribution.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * Traffic Distribution Routines.
6  *
7  * Contains routines for traffic distribution
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  HyperTransport
12  * @e \$Revision: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
13  *
14  */
15 /*
16  *****************************************************************************
17  *
18  * Copyright (C) 2012 Advanced Micro Devices, Inc.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions are met:
23  *     * Redistributions of source code must retain the above copyright
24  *       notice, this list of conditions and the following disclaimer.
25  *     * Redistributions in binary form must reproduce the above copyright
26  *       notice, this list of conditions and the following disclaimer in the
27  *       documentation and/or other materials provided with the distribution.
28  *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
29  *       its contributors may be used to endorse or promote products derived
30  *       from this software without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35  * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  * ***************************************************************************
44  *
45  */
46
47 /*
48  *----------------------------------------------------------------------------
49  *                                MODULES USED
50  *
51  *----------------------------------------------------------------------------
52  */
53
54
55
56 #include "AGESA.h"
57 #include "amdlib.h"
58 #include "Ids.h"
59 #include "Topology.h"
60 #include "htFeat.h"
61 #include "htInterface.h"
62 #include "htNb.h"
63 #include "htNotify.h"
64 #include "htFeatTrafficDistribution.h"
65 #include "Filecode.h"
66 CODE_GROUP (G1_PEICC)
67 RDATA_GROUP (G2_PEI)
68
69 #define FILECODE PROC_HT_FEATURES_HTFEATTRAFFICDISTRIBUTION_FILECODE
70 /*----------------------------------------------------------------------------
71  *                          DEFINITIONS AND MACROS
72  *
73  *----------------------------------------------------------------------------
74  */
75 /// Enum for the possible link connection status
76 typedef enum {
77   Unconnected = 0,                               ///< Nodes have not connected link.
78   UngangedLink,                                  ///< Nodes are connected with one unganged link.
79   Redundant,                                     ///< Nodes are connected with multi-unganged link.
80   GangedLink,                                    ///< Nodes are connected with one or mutiple ganged link.
81   MaxLink                                        ///< Max links status.
82 } LINK_STATUS;
83
84 /// Local port connection state data structure
85 typedef struct {
86   LINK_STATUS ConnectionState;                   /**< The link connection state. */
87   UINT8 BigLinkPort;                             /**< The Port number for ganged Link */
88 } PORT_CONNECTION_STATE;
89
90 /// Local ganged link for Victim Distribution data structure
91 typedef struct {
92 UINT8 NodeA;                                     ///< Source Node from Node A To Node B and DstNode from Node A To Node B.
93 UINT8 NodeB;                                     ///< Source Node from Node B To Node A and DstNode from Node A To Node B.
94 UINT8 VictimedLinkFromNodeAToNodeB;              ///< Victimed Link from Node A To Node B.
95 UINT8 VictimedLinkFromNodeBToNodeA;              ///< Victimed Link from Node B To Node A.
96 } VICTIM_ROUTED_LINK;
97
98 /*----------------------------------------------------------------------------
99  *                           TYPEDEFS AND STRUCTURES
100  *
101  *----------------------------------------------------------------------------
102  */
103
104 /*----------------------------------------------------------------------------
105  *                        PROTOTYPES OF LOCAL FUNCTIONS
106  *
107  *----------------------------------------------------------------------------
108  */
109
110 /*----------------------------------------------------------------------------
111  *                            EXPORTED FUNCTIONS
112  *
113  *----------------------------------------------------------------------------
114  */
115
116 /*----------------------------------------------------------------------------
117  *                              LOCAL FUNCTIONS
118  *
119  *----------------------------------------------------------------------------
120  */
121
122 /*----------------------------------------------------------------------------------------*/
123 /**
124  * Identify Links which can have traffic distribution.
125  *
126  * @HtFeatMethod{::F_TRAFFIC_DISTRIBUTION}
127  *
128  * If there are redundant links between any nodes, traffic distribution allows the
129  * redundant links to be used to improve performance.
130  *
131  * There are three types of traffic distribution. Their use is mutually exclusive, all
132  * can not be used at once.
133  *
134  * Coherent Traffic Distribution is for systems of exactly two nodes only.  All links must
135  * be symmetrical (the same width).  As many links as are connected can be distributed over.
136  *
137  * Victim Distribution is a way to direct victim traffic on to ganged links and away from unganged links
138  * as a way to reduce unganged link congestion for a system only if 2 processor (4 node) G34 system.
139  * A node can enables victim distribution mode only if the node connects to another node directly with
140  * only 1 unganged link hop and indirectly through 2 ganged link hops.
141  *
142  * Link Pair Traffic Distribution works with redundant pairs of links between any two nodes,
143  * it does not matter how many nodes are in the system or how many have a redundant link pair.
144  * A node can have redundant link pairs with more than one other node.
145  * The link pair can be asymmetric, the largest link must be used as the master.  However,
146  * between any pair of nodes there is only one pair of redundant links, and there is a limit
147  * to the total number of pairs each node can have.  So not all links will necessarily be
148  * made usable.
149  *
150  * @param[in]   State   port list data
151  */
152 VOID
153 TrafficDistribution (
154   IN       STATE_DATA *State
155   )
156 {
157   UINT32 Links01;
158   UINT32 Links10;
159   UINT32 LinksAB;
160   UINT32 LinksBA;
161   UINT8  LinkCount;
162   UINT8  UngandLinkCount;
163   UINT8  VictimedRouteCount;
164   UINT8  i;
165   UINT8  LastLink;
166   BOOLEAN IsAsymmetric;
167   BOOLEAN IsVictimedRouteFound;
168   UINT8 RedundantLinkCount[MAX_NODES][MAX_NODES];
169   UINT8 MasterLinkPort[MAX_NODES][MAX_NODES];
170   UINT8 AlternateLinkPort[MAX_NODES][MAX_NODES];
171   UINT8 NodeA;
172   UINT8 NodeB;
173   UINT8 PairCount;
174   VICTIM_ROUTED_LINK VictimRoutedLink[MAX_NODES];
175   PORT_CONNECTION_STATE GangedLinkPort[MAX_NODES][MAX_NODES];
176
177   LastLink = 0xFF;
178   IsAsymmetric = FALSE;
179
180   // Traffic Distribution is only used when there are exactly two Nodes in the system
181   // and when all the links are symmetric, same width.
182   if ((State->NodesDiscovered + 1) == 2) {
183     Links01 = 0;
184     Links10 = 0;
185     LinkCount = 0;
186     for (i = 0; i < (State->TotalLinks * 2); i += 2) {
187       if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) &&
188           ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) {
189         if ((LastLink != 0xFF) &&
190             ((*State->PortList)[i].SelWidthOut != (*State->PortList)[LastLink].SelWidthOut) &&
191             ((*State->PortList)[i + 1].SelWidthOut != (*State->PortList)[LastLink + 1].SelWidthOut)) {
192           IsAsymmetric = TRUE;
193           break;
194         }
195         Links01 |= (UINT32)1 << (*State->PortList)[i].Link;
196         Links10 |= (UINT32)1 << (*State->PortList)[i + 1].Link;
197         LinkCount++;
198         LastLink = i;
199       }
200     }
201     ASSERT (LinkCount != 0);
202     //  Don't setup Traffic Distribution if only one Link is being used or there were asymmetric widths
203     if ((LinkCount != 1) && !IsAsymmetric) {
204       IDS_HDT_CONSOLE (HT_TRACE, "Applying coherent traffic distribution.\n");
205       State->Nb->WriteTrafficDistribution (Links01, Links10, State->Nb);
206       // If we did Traffic Distribution, we must not do Link Pair, so get out of here.
207       return;
208     }
209   }
210
211   // Victim Distribution is only used when there are exactly two processor (4 node) system
212   // and the node connects to another node directly with only 1 unganged link hop and indirectly
213   // through 2 ganged link hops.
214   if ((State->NodesDiscovered + 1) == 4) {
215     UngandLinkCount = 0;
216
217     // Initialize the ganged link state data structures
218     for (NodeA = 0; NodeA < MAX_NODES; NodeA++) {
219       for (NodeB = 0; NodeB < MAX_NODES; NodeB++) {
220         GangedLinkPort[NodeA][NodeB].ConnectionState = 0;
221         GangedLinkPort[NodeA][NodeB].BigLinkPort = 0;
222       }
223     }
224
225     for (i = 0; i < (State->TotalLinks * 2); i += 2) {
226       if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) &&
227           ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) {
228         NodeA = (*State->PortList)[i].NodeID;
229         NodeB = (*State->PortList)[i + 1].NodeID;
230         if ((((*State->PortList)[i].SelRegang == TRUE) &&
231               ((*State->PortList)[i].PrvWidthOutCap == HT_WIDTH_16_BITS)) ||
232               ((*State->PortList)[i].SelWidthOut == HT_WIDTH_16_BITS)) {
233           if (GangedLinkPort[NodeA][NodeB].ConnectionState <= Redundant) {
234             // Record it if it is the first ganged link connecting two nodes.
235             GangedLinkPort[NodeA][NodeB].BigLinkPort = (*State->PortList)[i].Link;
236             GangedLinkPort[NodeB][NodeA].BigLinkPort = (*State->PortList)[i + 1].Link;
237             GangedLinkPort[NodeA][NodeB].ConnectionState = GangedLink;
238             GangedLinkPort[NodeB][NodeA].ConnectionState = GangedLink;
239           }
240         } else {
241           if (GangedLinkPort[NodeA][NodeB].ConnectionState == Unconnected) {
242             // Save it if it is firstly unganged link and also does no exist ganged link between node A and node B.
243             GangedLinkPort[NodeA][NodeB].ConnectionState = UngangedLink;
244             GangedLinkPort[NodeB][NodeA].ConnectionState = UngangedLink;
245
246             UngandLinkCount++;
247           } else if (GangedLinkPort[NodeA][NodeB].ConnectionState == UngangedLink) {
248             // Ignore it if there are multi-unganged links between node A and node B.
249             GangedLinkPort[NodeA][NodeB].ConnectionState = Redundant;
250             GangedLinkPort[NodeB][NodeA].ConnectionState = Redundant;
251
252             // Adjust the count because had it recorded once.
253             UngandLinkCount--;
254           }
255         }
256       }
257     }
258
259     if (UngandLinkCount != 0) {
260       VictimedRouteCount = 0;
261
262       // Check Link by Link if one unganged link can direct victim traffic on to indirectly 2 ganged link hops
263       for (NodeA = 0; NodeA <= (State->NodesDiscovered); NodeA++) {
264         for (NodeB = NodeA +1; NodeB <= (State->NodesDiscovered); NodeB++) {
265           if (GangedLinkPort[NodeA][NodeB].ConnectionState == UngangedLink) {
266             // This is unganged link connecting two nodes
267             IsVictimedRouteFound = FALSE;
268
269             for (i = 0; i <= (State->NodesDiscovered); i++) {
270               if ((i != NodeA) && (i != NodeB) && (GangedLinkPort[NodeA][i].ConnectionState == GangedLink)) {
271                 // This is the first ganged link hop to Destined Node
272                 VictimRoutedLink[VictimedRouteCount].NodeA = NodeA;
273                 VictimRoutedLink[VictimedRouteCount].VictimedLinkFromNodeAToNodeB = GangedLinkPort[NodeA][i].BigLinkPort;
274                 if (GangedLinkPort[i][NodeB].ConnectionState == GangedLink) {
275                   // This is the second ganged link hop to Destined Node
276                   // Save the Destined Node and the Reversed Destination Link
277                   VictimRoutedLink[VictimedRouteCount].NodeB = NodeB;
278                   VictimRoutedLink[VictimedRouteCount].VictimedLinkFromNodeBToNodeA = GangedLinkPort[NodeB][i].BigLinkPort;
279                   if (!IsVictimedRouteFound) {
280                     VictimedRouteCount++;
281
282                     // This is first victimed route where there are indirectly 2 ganged link hops to Destined Node
283                     IsVictimedRouteFound = TRUE;
284                   } else {
285                     // This is second victimed route, so we need to replace to the new Reversed Destination Link
286                     VictimRoutedLink[VictimedRouteCount - 1].VictimedLinkFromNodeBToNodeA = GangedLinkPort[NodeB][i].BigLinkPort;
287                   }
288                 }
289               }
290             }
291           }
292         }
293       }
294
295       // Setup Victim Distribution Mode
296       if (VictimedRouteCount != 0) {
297         IDS_HDT_CONSOLE (HT_TRACE, "Applying coherent Victim distribution.\n");
298         LinksAB = 0;
299         LinksBA = 0;
300         for (i = 0; i < VictimedRouteCount; i++) {
301           LinksAB = (UINT32)1 << VictimRoutedLink[i].VictimedLinkFromNodeAToNodeB;
302           LinksBA = (UINT32)1 << VictimRoutedLink[i].VictimedLinkFromNodeBToNodeA;
303           State->Nb->WriteVictimDistribution (
304             VictimRoutedLink[i].NodeA,
305             VictimRoutedLink[i].NodeB,
306             LinksAB,
307             LinksBA,
308             State->Nb
309             );
310         }
311         // If we did Victim Distribution, we must not do Link Pair when there are more than two nodes, so exit here.
312         return;
313       }
314     }
315   }
316
317   // Either there are more than two nodes, Asymmetric links, or no redundant links.
318   // See if we can use Link Pair Traffic Distribution
319   LibAmdMemFill (&RedundantLinkCount, 0, (MAX_NODES * MAX_NODES), State->ConfigHandle);
320   for (i = 0; i < (State->TotalLinks * 2); i += 2) {
321     if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) &&
322         ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) {
323       NodeA = (*State->PortList)[i].NodeID;
324       NodeB = (*State->PortList)[i + 1].NodeID;
325       if (RedundantLinkCount[NodeA][NodeB] == 0) {
326         // This is the first link connecting two nodes
327         ASSERT (RedundantLinkCount[NodeB][NodeA] == 0);
328         MasterLinkPort[NodeA][NodeB] = i;
329         MasterLinkPort[NodeB][NodeA] = i + 1;
330       } else {
331         // This is a redundant link.  If it is larger than the current master link,
332         // make it the new master link.
333         //
334         if (((*State->PortList)[MasterLinkPort[NodeA][NodeB]].SelWidthOut < (*State->PortList)[i].SelWidthOut) &&
335             ((*State->PortList)[MasterLinkPort[NodeB][NodeA]].SelWidthOut < (*State->PortList)[i + 1].SelWidthOut)) {
336           // Make the old master link the alternate, we don't need to check, it is bigger.
337           AlternateLinkPort[NodeA][NodeB] = MasterLinkPort[NodeA][NodeB];
338           AlternateLinkPort[NodeB][NodeA] = MasterLinkPort[NodeB][NodeA];
339           MasterLinkPort[NodeA][NodeB] = i;
340           MasterLinkPort[NodeB][NodeA] = i + 1;
341         } else {
342           // Since the new link isn't bigger than the Master, check if it is bigger than the alternate,
343           // if we have an alternate. If we don't have an alternate yet, make this link the alternate.
344           if (RedundantLinkCount[NodeA][NodeB] == 1) {
345             AlternateLinkPort[NodeA][NodeB] = i;
346             AlternateLinkPort[NodeB][NodeA] = i + 1;
347           } else {
348             if (((*State->PortList)[AlternateLinkPort[NodeA][NodeB]].SelWidthOut < (*State->PortList)[i].SelWidthOut) &&
349                 ((*State->PortList)[AlternateLinkPort[NodeB][NodeA]].SelWidthOut < (*State->PortList)[i + 1].SelWidthOut)) {
350               // Warning: the alternate link is an unusable redundant link
351               // Then make the new link the alternate link.
352               NotifyWarningOptUnusedLinks (
353                 NodeA,
354                 (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].Link,
355                 NodeB,
356                 (*State->PortList)[AlternateLinkPort[NodeB][NodeA]].Link,
357                 State
358                 );
359               ASSERT (RedundantLinkCount[NodeB][NodeA] > 1);
360               AlternateLinkPort[NodeA][NodeB] = i;
361               AlternateLinkPort[NodeB][NodeA] = i + 1;
362             } else {
363               // Warning the current link is an unusable redundant link
364               NotifyWarningOptUnusedLinks (NodeA, (*State->PortList)[i].Link, NodeB, (*State->PortList)[i].Link, State);
365             }
366           }
367         }
368       }
369       RedundantLinkCount[NodeA][NodeB]++;
370       RedundantLinkCount[NodeB][NodeA]++;
371     }
372   }
373   // If we found any, now apply up to 4 per node
374   for (NodeA = 0; NodeA < MAX_NODES; NodeA++) {
375     PairCount = 0;
376     for (NodeB = 0; NodeB < MAX_NODES; NodeB++) {
377       if (RedundantLinkCount[NodeA][NodeB] > 1) {
378         // Then there is a pair of links (at least, but we only care about the pair not the extras)
379         if (PairCount < MAX_LINK_PAIRS) {
380           // Program it
381           if ((*State->PortList)[MasterLinkPort[NodeA][NodeB]].SelWidthOut
382               != (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].SelWidthOut) {
383             IsAsymmetric = TRUE;
384           } else {
385             IsAsymmetric = FALSE;
386           }
387           State->Nb->WriteLinkPairDistribution (
388             NodeA,
389             NodeB,
390             PairCount,
391             IsAsymmetric,
392             (*State->PortList)[MasterLinkPort[NodeA][NodeB]].Link,
393             (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].Link,
394             State->Nb
395             );
396           PairCount++;
397         } else {
398           // Warning: More link pairs than can be distributed
399           NotifyWarningOptLinkPairExceed (
400             NodeA, NodeB,
401             (*State->PortList)[MasterLinkPort[NodeA][NodeB]].Link,
402             (*State->PortList)[AlternateLinkPort[NodeA][NodeB]].Link,
403             State);
404           // Disable the link pair from the other node, the analysis loop made sure there
405           // can only be a single link pair between a pair of nodes.
406           RedundantLinkCount[NodeB][NodeA] = 1;
407         }
408       }
409     }
410     IDS_HDT_CONSOLE (
411       HT_TRACE,
412       ((PairCount != 0) ?
413        "Node %d applying %d link pair distributions.\n" :
414        ""),
415       NodeA,
416       PairCount
417       );
418   }
419 }
420