AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / Features / htFeatOptimization.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * Link Optimization Routines.
6  *
7  * Contains routines for determining width, frequency, and other
8  * Link features
9  *
10  * @xrefitem bom "File Content Label" "Release Content"
11  * @e project:      AGESA
12  * @e sub-project:  HyperTransport
13  * @e \$Revision: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
14  *
15  */
16 /*
17 *****************************************************************************
18 *
19 * Copyright (C) 2012 Advanced Micro Devices, Inc.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 *     * Redistributions of source code must retain the above copyright
25 *       notice, this list of conditions and the following disclaimer.
26 *     * Redistributions in binary form must reproduce the above copyright
27 *       notice, this list of conditions and the following disclaimer in the
28 *       documentation and/or other materials provided with the distribution.
29 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
30 *       its contributors may be used to endorse or promote products derived
31 *       from this software without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
37 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 *
44 * ***************************************************************************
45 *
46 */
47
48 /*
49  *----------------------------------------------------------------------------
50  *                                MODULES USED
51  *
52  *----------------------------------------------------------------------------
53  */
54
55
56
57 #include "AGESA.h"
58 #include "amdlib.h"
59 #include "Ids.h"
60 #include "Topology.h"
61 #include "htFeat.h"
62 #include "IdsHt.h"
63 #include "htInterface.h"
64 #include "htNb.h"
65 #include "htFeatOptimization.h"
66 #include "htNotify.h"
67 #include "Filecode.h"
68 CODE_GROUP (G1_PEICC)
69 RDATA_GROUP (G2_PEI)
70
71 #define FILECODE PROC_HT_FEATURES_HTFEATOPTIMIZATION_FILECODE
72
73 extern CONST PF_HtIdsGetPortOverride ROMDATA pf_HtIdsGetPortOverride;
74
75 /*----------------------------------------------------------------------------
76  *                          DEFINITIONS AND MACROS
77  *
78  *----------------------------------------------------------------------------
79  */
80 #define PCI_CONFIG_COMMAND_REG04  4
81 #define PCI_CONFIG_REVISION_REG08 8
82
83 /*----------------------------------------------------------------------------
84  *                           TYPEDEFS AND STRUCTURES
85  *
86  *----------------------------------------------------------------------------
87  */
88
89 /*----------------------------------------------------------------------------
90  *                        PROTOTYPES OF LOCAL FUNCTIONS
91  *
92  *----------------------------------------------------------------------------
93  */
94
95 /*----------------------------------------------------------------------------
96  *                            EXPORTED FUNCTIONS
97  *
98  *----------------------------------------------------------------------------
99  */
100
101 /*----------------------------------------------------------------------------
102  *                              LOCAL FUNCTIONS
103  *
104  *----------------------------------------------------------------------------
105  */
106
107 /***************************************************************************
108  ***                            Link Optimization                        ***
109  ***************************************************************************/
110
111 /*----------------------------------------------------------------------------------------*/
112 /**
113  * Given the bits set in the register field, return the width it represents.
114  *
115  * As invalid width values or encodings are rare except during debug, catch those using
116  * ASSERT().  This means theoretically we are returning an incorrect result if that
117  * happens.  The default chosen for the result is arbitrarily 8 bits.  This is likely
118  * not to be the actual correct width and may cause a crash, hang, or incorrect operation.
119  * Hardware often ignores writes of invalid width encodings.
120  *
121  * @note This routine is used for CPUs as well as IO devices, as all comply to the
122  * "HyperTransport I/O Link Specification ".
123  *
124  * @param[in]     Value The bits for the register
125  *
126  * @return The width
127  */
128 UINT8
129 STATIC
130 ConvertBitsToWidth (
131   IN       UINT8       Value
132   )
133 {
134   UINT8 Result;
135
136   Result = 0;
137
138   switch (Value) {
139
140   case  1:
141     Result = 16;
142     break;
143
144   case  0:
145     Result = 8;
146     break;
147
148   case 3:
149     Result = 32;
150     break;
151
152   case  5:
153     Result = 4;
154     break;
155
156   case  4:
157     Result = 2;
158     break;
159
160   default:
161     ASSERT (FALSE);
162   }
163   return Result;
164 }
165
166 /*----------------------------------------------------------------------------------------*/
167 /**
168  * Translate a desired width setting to the bits to set in the register field.
169  *
170  * As invalid width values or encodings are rare except during debug, catch those using
171  * ASSERT().  This means theoretically we are returning an incorrect result if that
172  * happens.  The default chosen for the result is arbitrarily 8 bits.  This is likely
173  * not to be the actual correct width and may cause a crash, hang, or incorrect operation.
174  * Hardware often ignores writes of invalid width encodings.
175  *
176  * @note This routine is used for CPUs as well as IO devices, as all comply to the
177  * "HyperTransport I/O Link Specification ".
178  *
179  * @param[in]     Value   the width Value
180  *
181  * @return The bits for the register
182  */
183 UINT8
184 ConvertWidthToBits (
185   IN       UINT8       Value
186   )
187 {
188   UINT8 Result;
189
190   Result = 8;
191
192   switch (Value) {
193
194   case 16:
195     Result = 1;
196     break;
197
198   case 8:
199     Result = 0;
200     break;
201
202   case 32:
203     Result = 3;
204     break;
205
206   case 4:
207     Result = 5;
208     break;
209
210   case 2:
211     Result = 4;
212     break;
213
214   default:
215     ASSERT (FALSE);
216   }
217   return Result;
218 }
219
220 /*----------------------------------------------------------------------------------------*/
221 /**
222  * Access HT Link Control Register.
223  *
224  * @HtFeatMethod{::F_SET_HT_CONTROL_REGISTER_BITS}
225  *
226  * Provide a common routine for accessing the HT Link Control registers (84, a4, c4,
227  * e4), to enforce not clearing the HT CRC error bits.  Replaces direct use of
228  * AmdPCIWriteBits().
229  *
230  * @note: This routine is called for CPUs as well as IO Devices! All comply to the
231  * "HyperTransport I/O Link Specification ".
232  *
233  * @param[in]     Reg      the PCI config address the control register
234  * @param[in]     HiBit    the high bit number
235  * @param[in]     LoBit    the low bit number
236  * @param[in]     Value    the value to write to that bit range. Bit 0 => loBit.
237  * @param[in]     State    Our state, config handle for lib
238  */
239 VOID
240 SetHtControlRegisterBits (
241   IN       PCI_ADDR    Reg,
242   IN       UINT8       HiBit,
243   IN       UINT8       LoBit,
244   IN       UINT32      *Value,
245   IN       STATE_DATA  *State
246   )
247 {
248   UINT32 Temp;
249   UINT32 mask;
250
251   ASSERT ((HiBit < 32) && (LoBit < 32) && (HiBit >= LoBit) && ((Reg.AddressValue & 0x3) == 0));
252   ASSERT ((HiBit < 8) || (LoBit > 9));
253
254   // A 1 << 32 == 1 << 0 due to x86 SHL instruction, so skip if that is the case
255   if ((HiBit - LoBit) != 31) {
256     mask = (((UINT32)1 << (HiBit - LoBit + 1)) - 1);
257   } else {
258     mask = (UINT32)0xFFFFFFFF;
259   }
260
261   LibAmdPciRead (AccessWidth32, Reg, &Temp, State->ConfigHandle);
262   Temp &= ~(mask << LoBit);
263   Temp |= (*Value & mask) << LoBit;
264   Temp &= (UINT32)HT_CONTROL_CLEAR_CRC;
265   LibAmdPciWrite (AccessWidth32, Reg, &Temp, State->ConfigHandle);
266 }
267
268 /*----------------------------------------------------------------------------------------*/
269 /**
270  * Set HT Frequency register for IO Devices
271  *
272  * Provide a common routine for accessing the HT Link Frequency registers at offset 8
273  * and 0x10, to enforce not clearing the HT Link error bits.  Replaces direct use of
274  * AmdPCIWriteBits().
275  *
276  * @note This routine is called for IO Devices only!! All comply to the
277  * "HyperTransport I/O Link Specification ".
278  *
279  * @param[in]    Reg       the PCI config address the control register
280  * @param[in]    Hibit     the high bit number
281  * @param[in]    Lobit     the low bit number
282  * @param[in]    Value     the value to write to that bit range. Bit 0 => loBit.
283  * @param[in]    State     Our state, config handle for lib
284  */
285 VOID
286 STATIC
287 SetHtIoFrequencyRegisterBits (
288   IN       PCI_ADDR    Reg,
289   IN       UINT8       Hibit,
290   IN       UINT8       Lobit,
291   IN       UINT32      *Value,
292   IN       STATE_DATA  *State
293   )
294 {
295   UINT32 Mask;
296   UINT32 Temp;
297
298   ASSERT ((Hibit < 32) && (Lobit < 32) && (Hibit >= Lobit) && ((Reg.AddressValue & 0x3) == 0));
299   ASSERT ((Hibit < 12) || (Lobit > 14));
300
301   // A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case
302   if ((Hibit - Lobit) != 31) {
303     Mask = (((UINT32)1 << ((Hibit - Lobit) + 1)) - 1);
304   } else {
305     Mask = (UINT32)0xFFFFFFFF;
306   }
307
308   LibAmdPciRead (AccessWidth32, Reg, &Temp, State->ConfigHandle);
309   Temp &= ~(Mask << Lobit);
310   Temp |= (*Value & Mask) << Lobit;
311   Temp &= (UINT32)HT_FREQUENCY_CLEAR_LINK_ERRORS;
312   LibAmdPciWrite (AccessWidth32, Reg, &Temp, State->ConfigHandle);
313 }
314
315 /*----------------------------------------------------------------------------------------*/
316 /**
317  * Get Link features into system data structure.
318  *
319  * @HtFeatMethod{::F_GATHER_LINK_DATA}
320  *
321  * For all discovered Links, populate the port list with the frequency and width
322  * capabilities. Gather support data for:
323  * - Unit ID Clumping
324  *
325  * @param[in]     State our global state, port list
326  */
327 VOID
328 GatherLinkData (
329   IN       STATE_DATA *State
330   )
331 {
332   UINT8 i;
333   PCI_ADDR LinkBase;
334   PCI_ADDR Reg;
335   UINT32 Bits;
336   UINT8 Revision;
337
338   // Get the capability base for whatever device type the link port is on
339   for (i = 0; i < (State->TotalLinks * 2); i++) {
340     if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) {
341       LinkBase = State->Nb->MakeLinkBase ((*State->PortList)[i].NodeID, (*State->PortList)[i].Link, State->Nb);
342       (*State->PortList)[i].Pointer = LinkBase;
343     } else {
344       LinkBase = (*State->PortList)[i].Pointer;
345       if ((*State->PortList)[i].Link == 1) {
346         LinkBase.Address.Register += HTSLAVE_LINK01_OFFSET;
347       }
348     }
349
350     // Getting the Width is standard across device types
351     Reg = LinkBase;
352     Reg.Address.Register += HTSLAVE_LINK_CONTROL_0_REG;
353     LibAmdPciReadBits (Reg, 22, 20, &Bits, State->ConfigHandle);
354     (*State->PortList)[i].PrvWidthOutCap = ConvertBitsToWidth ((UINT8)Bits);
355
356     LibAmdPciReadBits (Reg, 18, 16, &Bits, State->ConfigHandle);
357     (*State->PortList)[i].PrvWidthInCap = ConvertBitsToWidth ((UINT8)Bits);
358
359     // Get Frequency and other device type specific features
360     if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) {
361       State->Nb->GatherLinkFeatures (&(*State->PortList)[i], State->HtInterface, State->PlatformConfiguration, State->Nb);
362     } else {
363       Reg = LinkBase;
364       Reg.Address.Register += HTSLAVE_FREQ_REV_0_REG;
365       LibAmdPciReadBits (Reg, 31, 16, &Bits, State->ConfigHandle);
366       (*State->PortList)[i].PrvFrequencyCap = Bits;
367
368       // Unit ID Clumping Support
369       if (State->IsUsingUnitIdClumping) {
370         if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_UNITID_CAPABILITY, &Reg, State)) {
371           Reg.Address.Register += HTUNIT_SUPPORT_REG;
372           LibAmdPciReadBits (Reg, 31, 0, &Bits, State->ConfigHandle);
373         } else {
374           // Not there, that's ok, we don't know that it should have one.
375           // Check for Passive support. (Bit 0 won't be set if full support is implemented,
376           // so we can use it to indicate passive support in our portlist struct).
377           Reg = LinkBase;
378           Reg.Address.Register += HTSLAVE_FEATURECAP_REG;
379           Bits = 1;
380           LibAmdPciWriteBits (Reg, 5, 5, &Bits, State->ConfigHandle);
381           LibAmdPciReadBits (Reg, 5, 5, &Bits, State->ConfigHandle);
382         }
383         (*State->PortList)[i].ClumpingSupport = Bits;
384       } else {
385         (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE;
386       }
387
388       Reg = LinkBase;
389       Reg.Address.Register = PCI_CONFIG_REVISION_REG08;
390       LibAmdPciReadBits ( LinkBase, 7, 0, &Bits, State->ConfigHandle);
391       Revision = (UINT8) Bits;
392
393       LinkBase.Address.Register = 0;
394       LibAmdPciRead (AccessWidth32, LinkBase, &Bits, State->ConfigHandle);
395
396       State->HtInterface->GetDeviceCapOverride ((*State->PortList)[i].NodeID,
397                            (*State->PortList)[i].HostLink,
398                            (*State->PortList)[i].HostDepth,
399                            (*State->PortList)[i].Pointer,
400                            Bits,
401                            Revision,
402                            (*State->PortList)[i].Link,
403                            &((*State->PortList)[i].PrvWidthInCap),
404                            &((*State->PortList)[i].PrvWidthOutCap),
405                            &((*State->PortList)[i].PrvFrequencyCap),
406                            &((*State->PortList)[i].ClumpingSupport),
407                            State);
408     }
409   }
410 }
411
412 /*----------------------------------------------------------------------------------------*/
413 /**
414  * Optimize Links.
415  *
416  * @HtFeatMethod{::F_SELECT_OPTIMAL_WIDTH_AND_FREQUENCY}
417  *
418  * For all Links:
419  * Examine both sides of a Link and determine the optimal frequency and width,
420  * taking into account externally provided limits and enforcing any other limit
421  * or matching rules as applicable except subLink balancing. Update the port
422  * list data with the optimal settings.
423  *
424  * @note no hardware state changes in this routine.
425  *
426  * @param[in,out]    State         Process and update portlist
427  */
428 VOID
429 SelectOptimalWidthAndFrequency (
430   IN OUT   STATE_DATA   *State
431   )
432 {
433   UINT8 i;
434   UINT8 j;
435   UINT8 Freq;
436   UINT32 Temp;
437   UINT32 CbPcbFreqLimit;
438   UINT8 CbPcbABDownstreamWidth;
439   UINT8 CbPcbBAUpstreamWidth;
440
441   for (i = 0; i < (State->TotalLinks * 2); i += 2) {
442     CbPcbFreqLimit = HT_FREQUENCY_NO_LIMIT;
443     CbPcbABDownstreamWidth = HT_WIDTH_16_BITS;
444     CbPcbBAUpstreamWidth = HT_WIDTH_16_BITS;
445
446     if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) {
447       State->HtInterface->GetCpu2CpuPcbLimits ((*State->PortList)[i].NodeID,
448                            (*State->PortList)[i].Link,
449                            (*State->PortList)[i + 1].NodeID,
450                            (*State->PortList)[i + 1].Link,
451                            &CbPcbABDownstreamWidth,
452                            &CbPcbBAUpstreamWidth,
453                            &CbPcbFreqLimit,
454                            State
455         );
456     } else {
457       State->HtInterface->GetIoPcbLimits ((*State->PortList)[i + 1].NodeID,
458                       (*State->PortList)[i + 1].HostLink,
459                       (*State->PortList)[i + 1].HostDepth,
460                       &CbPcbABDownstreamWidth,
461                       &CbPcbBAUpstreamWidth,
462                       &CbPcbFreqLimit,
463                       State
464         );
465     }
466
467     Temp = (*State->PortList)[i].PrvFrequencyCap;
468     Temp &= (*State->PortList)[i + 1].PrvFrequencyCap;
469     Temp &= CbPcbFreqLimit;
470     (*State->PortList)[i].CompositeFrequencyCap = (UINT32)Temp;
471     (*State->PortList)[i + 1].CompositeFrequencyCap = (UINT32)Temp;
472
473     ASSERT (Temp != 0);
474     Freq = LibAmdBitScanReverse (Temp);
475     (*State->PortList)[i].SelFrequency = Freq;
476     (*State->PortList)[i + 1].SelFrequency = Freq;
477
478     Temp = (*State->PortList)[i].PrvWidthOutCap;
479     if ((*State->PortList)[i + 1].PrvWidthInCap < Temp) {
480       Temp = (*State->PortList)[i + 1].PrvWidthInCap;
481     }
482     if (CbPcbABDownstreamWidth < Temp) {
483       Temp = CbPcbABDownstreamWidth;
484     }
485     (*State->PortList)[i].SelWidthOut = (UINT8)Temp;
486     (*State->PortList)[i + 1].SelWidthIn = (UINT8)Temp;
487
488     Temp = (*State->PortList)[i].PrvWidthInCap;
489     if ((*State->PortList)[i + 1].PrvWidthOutCap < Temp) {
490       Temp = (*State->PortList)[i + 1].PrvWidthOutCap;
491     }
492     if (CbPcbBAUpstreamWidth < Temp) {
493       Temp = CbPcbBAUpstreamWidth;
494     }
495     (*State->PortList)[i].SelWidthIn = (UINT8)Temp;
496     (*State->PortList)[i + 1].SelWidthOut = (UINT8)Temp;
497   }
498   // Calculate unit id clumping
499   //
500   // Find the root of each IO Chain, process the chain for clumping support.
501   // The root is always the first link of the chain in the port list.
502   // Clumping is not device link specific, so we can just look at the upstream ports (j+1). Use ASSERTs to sanity
503   // check the downstream ports (j).  If any device on the chain does not support clumping, the entire chain will be
504   // disabled for clumping.
505   // After analyzing the clumping support on the chain the CPU's portlist has the enable mask.  Update all the
506   // IO Devices on the chain with the enable mask.  If any device's only have passive support, that is already enabled.
507   //
508   if (State->IsUsingUnitIdClumping) {
509     for (i = 0; i < (State->TotalLinks * 2); i += 2) {
510       if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_IO)) {
511         (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE;
512         if ((*State->PortList)[i + 1].ClumpingSupport != HT_CLUMPING_DISABLE) {
513           (*State->PortList)[i].ClumpingSupport |= (*State->PortList)[i + 1].ClumpingSupport;
514           for (j = i + 2; j < (State->TotalLinks * 2); j += 2) {
515             if (((*State->PortList)[j].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[j + 1].Type == PORTLIST_TYPE_IO)) {
516               if (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) &&
517                   ((*State->PortList)[i].Link == (*State->PortList)[j + 1].HostLink)) {
518                 ASSERT (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) &&
519                         ((*State->PortList)[i].Link == (*State->PortList)[j].HostLink));
520                 if ((*State->PortList)[j + 1].ClumpingSupport != HT_CLUMPING_DISABLE) {
521                   ASSERT ((((*State->PortList)[j + 1].ClumpingSupport & HT_CLUMPING_PASSIVE) == 0) ||
522                           (((*State->PortList)[j + 1].ClumpingSupport & ~(HT_CLUMPING_PASSIVE)) == 0));
523                   (*State->PortList)[i].ClumpingSupport |= (*State->PortList)[j + 1].ClumpingSupport;
524                 } else {
525                   (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE;
526                   break;
527                 }
528               }
529             }
530           }
531           if ((*State->PortList)[i + 1].ClumpingSupport != HT_CLUMPING_PASSIVE) {
532             (*State->PortList)[i + 1].ClumpingSupport = (*State->PortList)[i].ClumpingSupport;
533           }
534           for (j = i + 2; j < (State->TotalLinks * 2); j += 2) {
535             if (((*State->PortList)[j].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[j + 1].Type == PORTLIST_TYPE_IO)) {
536               if (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) &&
537                   ((*State->PortList)[i].Link == (*State->PortList)[j + 1].HostLink)) {
538                 if ((*State->PortList)[j + 1].ClumpingSupport != HT_CLUMPING_PASSIVE) {
539                   (*State->PortList)[j + 1].ClumpingSupport = (*State->PortList)[i].ClumpingSupport;
540                   // The downstream isn't really passive, just mark it so in order to write the device only once.
541                   (*State->PortList)[j].ClumpingSupport = HT_CLUMPING_PASSIVE;
542                 }
543               }
544             }
545           }
546         }
547       }
548     }
549   }
550 }
551
552 /*----------------------------------------------------------------------------------------*/
553 /**
554  * Change the hardware state for all Links according to the now optimized data in the
555  * port list data structure.
556  *
557  * @HtFeatMethod{::F_SET_LINK_DATA}
558  *
559  * @param[in]     State   our global state, port list
560  */
561 VOID
562 SetLinkData (
563   IN       STATE_DATA *State
564   )
565 {
566   UINT8 i;
567   PCI_ADDR LinkBase;
568   PCI_ADDR Reg;
569   UINT32 Temp;
570   UINT32 Widthin;
571   UINT32 Widthout;
572   UINT32 Bits;
573   PCI_ADDR CurrentPtr;
574   HTIDS_PORT_OVERRIDE_LIST PortOverrides;
575
576   PortOverrides = NULL;
577
578   for (i = 0; i < (State->TotalLinks * 2); i++) {
579
580     ASSERT ((*State->PortList)[i & 0xFE].SelWidthOut == (*State->PortList)[ (i & 0xFE) + 1].SelWidthIn);
581     ASSERT ((*State->PortList)[i & 0xFE].SelWidthIn == (*State->PortList)[ (i & 0xFE) + 1].SelWidthOut);
582     ASSERT ((*State->PortList)[i & 0xFE].SelFrequency == (*State->PortList)[ (i & 0xFE) + 1].SelFrequency);
583
584     if ((*State->PortList)[i].SelRegang) {
585       ASSERT ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU);
586       ASSERT ((*State->PortList)[i].Link < 4);
587       State->Nb->SetLinkRegang (
588         (*State->PortList)[i].NodeID,
589         (*State->PortList)[i].Link,
590         State->Nb
591         );
592     }
593
594     //
595     // IDS port override for CPUs and IO Devices
596     //
597     pf_HtIdsGetPortOverride ((BOOLEAN) ((i & 1) == 0), &(*State->PortList)[i], &(*State->PortList)[i + 1], &PortOverrides, State);
598
599     LinkBase = (*State->PortList)[i].Pointer;
600     if (((*State->PortList)[i].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[i].Link == 1)) {
601       LinkBase.Address.Register += HTSLAVE_LINK01_OFFSET;
602     }
603
604     // HT CRC Feature, set if configured.  The default is not to set it, because with some chipsets it
605     // will lock up if done here.
606     if (State->IsSetHtCrcFlood) {
607       Temp = 1;
608       Reg = LinkBase;
609       Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
610       State->HtFeatures->SetHtControlRegisterBits (Reg, 1, 1, &Temp, State);
611       if ((*State->PortList)[i].Type == PORTLIST_TYPE_IO) {
612         // IO Devices also need to have SERR enabled.
613         Reg = LinkBase;
614         Reg.Address.Register = PCI_CONFIG_COMMAND_REG04;
615         LibAmdPciWriteBits (Reg, 8, 8, &Temp, State->ConfigHandle);
616       }
617     }
618
619     // Some IO devices don't work properly when setting widths, so write them in a single operation,
620     // rather than individually.
621     //
622     Widthout = ConvertWidthToBits ((*State->PortList)[i].SelWidthOut);
623     ASSERT (Widthout == 1 || Widthout == 0 || Widthout == 5 || Widthout == 4);
624     Widthin = ConvertWidthToBits ((*State->PortList)[i].SelWidthIn);
625     ASSERT (Widthin == 1 || Widthin == 0 || Widthin == 5 || Widthin == 4);
626
627     Temp = (Widthin & 7) | ((Widthout & 7) << 4);
628     Reg = LinkBase;
629     Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
630     State->HtFeatures->SetHtControlRegisterBits (Reg, 31, 24, &Temp, State);
631
632     Temp = (*State->PortList)[i].SelFrequency;
633     IDS_HDT_CONSOLE (HT_TRACE, "Link Frequency: Node %02d: Link %02d: is running at %2d00MHz\n",
634         (*State->PortList)[i].NodeID, (*State->PortList)[i].Link,
635         (Temp < HT_FREQUENCY_800M) ? Temp + 2 : ((Temp < HT_FREQUENCY_2800M) ? 2 * (Temp - 1) : 2 * (Temp - 3)));
636
637     if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) {
638       State->Nb->SetLinkFrequency (
639         (*State->PortList)[i].NodeID,
640         (*State->PortList)[i].Link,
641         (UINT8)Temp,
642         State->Nb
643         );
644     } else {
645       ASSERT (Temp <= HT_FREQUENCY_2600M);
646       // Write the frequency setting
647       Reg = LinkBase;
648       Reg.Address.Register += HTSLAVE_FREQ_REV_0_REG;
649       SetHtIoFrequencyRegisterBits (Reg, 11, 8, &Temp, State);
650
651       // Handle additional HT3 frequency requirements, if needed,
652       // or clear them if switching down to ht1 on a warm reset.
653       // Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz
654       //
655       // Even though we assert if debugging, we need to check that the capability was
656       // found always, since this is an unknown hardware device, also we are taking
657       // unqualified frequency from the external interface (could be trying to do ht3
658       // on an ht1 IO device).
659       //
660
661       if (Temp > HT_FREQUENCY_1000M) {
662         // Enabling features if gen 3
663         Bits = 1;
664       } else {
665         // Disabling features if gen 1
666         Bits = 0;
667       }
668
669       // Retry Enable
670       if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_RETRY_CAPABILITY, &CurrentPtr, State)) {
671         ASSERT ((*State->PortList)[i].Link < 2);
672         CurrentPtr.Address.Register += HTRETRY_CONTROL_REG;
673         LibAmdPciWriteBits (CurrentPtr,
674                             ((*State->PortList)[i].Link * 16),
675                             ((*State->PortList)[i].Link * 16),
676                             &Bits,
677                             State->ConfigHandle);
678       } else {
679         //  If we are turning it off, that may mean the device was only ht1 capable,
680         // so don't complain that we can't do it.
681         //
682         if (Bits != 0) {
683           NotifyWarningOptRequiredCapRetry ((*State->PortList)[i].NodeID,
684                                             (*State->PortList)[i].HostLink,
685                                             (*State->PortList)[i].HostDepth,
686                                             State);
687         }
688       }
689
690       // Scrambling enable
691       if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_GEN3_CAPABILITY, &CurrentPtr, State)) {
692         ASSERT ((*State->PortList)[i].Link < 2);
693         CurrentPtr.Address.Register = CurrentPtr.Address.Register +
694           HTGEN3_LINK_TRAINING_0_REG +
695           ((*State->PortList)[i].Link * HTGEN3_LINK01_OFFSET);
696         LibAmdPciWriteBits (CurrentPtr, 3, 3, &Bits, State->ConfigHandle);
697       } else {
698         //  If we are turning it off, that may mean the device was only ht1 capable,
699         // so don't complain that we can't do it.
700         //
701         if (Bits != 0) {
702           NotifyWarningOptRequiredCapGen3 ((*State->PortList)[i].NodeID,
703                                            (*State->PortList)[i].HostLink,
704                                            (*State->PortList)[i].HostDepth,
705                                            State);
706         }
707       }
708     }
709     // Enable Unit ID Clumping if supported.
710     if (State->IsUsingUnitIdClumping) {
711       if (((*State->PortList)[i].ClumpingSupport != HT_CLUMPING_PASSIVE) &&
712           ((*State->PortList)[i].ClumpingSupport != HT_CLUMPING_DISABLE)) {
713         Bits = (*State->PortList)[i].ClumpingSupport;
714         if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) {
715           State->Nb->SetLinkUnitIdClumping (
716             (*State->PortList)[i].NodeID,
717             (*State->PortList)[i].Link,
718             (*State->PortList)[i].ClumpingSupport,
719             State->Nb
720             );
721         } else {
722           if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_UNITID_CAPABILITY, &Reg, State)) {
723             Reg.Address.Register += HTUNIT_ENABLE_REG;
724             LibAmdPciWriteBits (Reg, 31, 0, &Bits, State->ConfigHandle);
725           } else {
726             // If we found one when gathering support, we have to find one now.
727             ASSERT (FALSE);
728           }
729         }
730       }
731     }
732   }
733 }
734
735 /*------------------------------------------------------------------------------------------*/
736 /**
737  * Find a specific HT capability type.
738  *
739  * Search all the PCI Config space capabilities on any type of device for an
740  * HT capability of the specific subtype.
741  *
742  * @param[in]  DevicePointer     A PCI Config address somewhere in the device config space
743  * @param[in]  CapSubType        The HT capability subtype to find
744  * @param[out] CapabilityBase    The Config space base address of the capability, if found.
745  * @param[in]  State             Our State
746  *
747  * @retval TRUE     the capability was found
748  * @retval FALSE    the capability was not found
749  */
750 BOOLEAN
751 DoesDeviceHaveHtSubtypeCap (
752   IN       PCI_ADDR         DevicePointer,
753   IN       UINT8            CapSubType,
754      OUT   PCI_ADDR         *CapabilityBase,
755   IN       STATE_DATA       *State
756   )
757 {
758   BOOLEAN IsFound;
759   BOOLEAN IsDone;
760   PCI_ADDR Reg;
761   UINT32 Temp;
762   UINT32 RegSubType;
763   UINT32 RegSubTypeMask;
764
765   // Set the PCI Config Space base and the match value.
766   IsFound = FALSE;
767   IsDone = FALSE;
768   Reg = DevicePointer;
769   Reg.Address.Register = 0;
770   if (CapSubType < (HT_HOST_CAPABILITY + 1)) {
771     // HT Interface sub type
772     RegSubType = ((UINT32) (CapSubType << 29) | (UINT32)8);
773     RegSubTypeMask = HT_INTERFACE_CAP_SUBTYPE_MASK;
774   } else {
775     // Other HT capability subtype
776     RegSubType = ((UINT32) (CapSubType << 27) | (UINT32)8);
777     RegSubTypeMask = HT_CAP_SUBTYPE_MASK;
778   }
779   (*CapabilityBase).AddressValue = (UINT32)ILLEGAL_SBDFO;
780
781   // Find it
782   do {
783     LibAmdPciFindNextCap (&Reg, State->ConfigHandle);
784     if (Reg.AddressValue != (UINT32)ILLEGAL_SBDFO) {
785       LibAmdPciRead (AccessWidth32, Reg, &Temp, State->ConfigHandle);
786       // HyperTransport and subtype capability ?
787       if ((Temp & RegSubTypeMask) == RegSubType) {
788         *CapabilityBase = Reg;
789         IsFound = TRUE;
790       }
791       // Some other capability, keep looking
792     } else {
793       //  Not there
794       IsDone = TRUE;
795     }
796   } while (!IsFound && !IsDone);
797
798   return IsFound;
799 }
800
801 /*----------------------------------------------------------------------------------------*/
802 /**
803  * Retry must be enabled on all coherent links if it is enabled on any coherent links.
804  *
805  * @HtFeatMethod{::F_SET_LINK_DATA}
806  *
807  * Effectively, this means HT3 on some links cannot be mixed with HT1 on others.
808  * Scan the CPU to CPU links for this condition and limit those frequencies to HT1
809  * if it is detected.
810  * (Non-coherent links are independent.)
811  *
812  * @param[in,out]   State       global state, port frequency settings.
813  *
814  * @retval          TRUE        Fixup occurred, all coherent links HT1
815  * @retval          FALSE       No changes
816  */
817 BOOLEAN
818 IsCoherentRetryFixup (
819   IN       STATE_DATA       *State
820   )
821 {
822   UINT8 Freq;
823   UINT8 i;
824   UINT8 DetectedFrequencyState;
825   BOOLEAN IsMixed;
826   UINT32 Temp;
827
828   //
829   // detectedFrequencyState:
830   //   0 - initial state
831   //   1 - HT1 Frequencies detected
832   //   2 - HT3 Frequencies detected
833   //
834   IsMixed = FALSE;
835   DetectedFrequencyState = 0;
836
837   // Scan coherent links for a mix of HT3 / HT1
838   for (i = 0; i < (State->TotalLinks * 2); i += 2) {
839     if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) {
840       // At this point, Frequency of port [i+1] must equal [i], so just check one of them.
841       switch (DetectedFrequencyState) {
842       case 0:
843         // Set current state to indicate what link frequency we found first
844         if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) {
845           // HT3 frequencies
846           DetectedFrequencyState = 2;
847         } else {
848           // HT1 frequencies
849           DetectedFrequencyState = 1;
850         }
851         break;
852       case 1:
853         // If HT1 frequency detected, fail any HT3 frequency
854         if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) {
855           IsMixed = TRUE;
856         }
857         break;
858       case 2:
859         // If HT3 frequency detected, fail any HT1 frequency
860         if ((*State->PortList)[i].SelFrequency <= HT_FREQUENCY_1000M) {
861           IsMixed = TRUE;
862         }
863         break;
864       default:
865         ASSERT (FALSE);
866       }
867       if (IsMixed) {
868         // Don't need to keep checking after we find a mix.
869         break;
870       }
871     }
872   }
873
874   if (IsMixed) {
875     for (i = 0; i < (State->TotalLinks * 2); i += 2) {
876       if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) {
877         // Limit coherent links to HT 1 frequencies.
878         Temp = (*State->PortList)[i].CompositeFrequencyCap & (*State->PortList)[i + 1].CompositeFrequencyCap;
879         Temp &= HT_FREQUENCY_LIMIT_HT1_ONLY;
880         ASSERT (Temp != 0);
881         (*State->PortList)[i].CompositeFrequencyCap = Temp;
882         (*State->PortList)[i + 1].CompositeFrequencyCap = Temp;
883         Freq = LibAmdBitScanReverse (Temp);
884         (*State->PortList)[i].SelFrequency = Freq;
885         (*State->PortList)[i + 1].SelFrequency = Freq;
886       }
887     }
888   }
889   return (IsMixed);
890 }