5 * Link Optimization Routines.
7 * Contains routines for determining width, frequency, and other
10 * @xrefitem bom "File Content Label" "Release Content"
12 * @e sub-project: HyperTransport
13 * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
17 *****************************************************************************
19 * Copyright (C) 2012 Advanced Micro Devices, Inc.
20 * All rights reserved.
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.
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.
44 * ***************************************************************************
49 *----------------------------------------------------------------------------
52 *----------------------------------------------------------------------------
63 #include "htInterface.h"
65 #include "htFeatOptimization.h"
71 #define FILECODE PROC_HT_FEATURES_HTFEATOPTIMIZATION_FILECODE
73 extern CONST PF_HtIdsGetPortOverride ROMDATA pf_HtIdsGetPortOverride;
75 /*----------------------------------------------------------------------------
76 * DEFINITIONS AND MACROS
78 *----------------------------------------------------------------------------
80 #define PCI_CONFIG_COMMAND_REG04 4
81 #define PCI_CONFIG_REVISION_REG08 8
83 /*----------------------------------------------------------------------------
84 * TYPEDEFS AND STRUCTURES
86 *----------------------------------------------------------------------------
89 /*----------------------------------------------------------------------------
90 * PROTOTYPES OF LOCAL FUNCTIONS
92 *----------------------------------------------------------------------------
95 /*----------------------------------------------------------------------------
98 *----------------------------------------------------------------------------
101 /*----------------------------------------------------------------------------
104 *----------------------------------------------------------------------------
107 /***************************************************************************
108 *** Link Optimization ***
109 ***************************************************************************/
111 /*----------------------------------------------------------------------------------------*/
113 * Given the bits set in the register field, return the width it represents.
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.
121 * @note This routine is used for CPUs as well as IO devices, as all comply to the
122 * "HyperTransport I/O Link Specification ".
124 * @param[in] Value The bits for the register
166 /*----------------------------------------------------------------------------------------*/
168 * Translate a desired width setting to the bits to set in the register field.
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.
176 * @note This routine is used for CPUs as well as IO devices, as all comply to the
177 * "HyperTransport I/O Link Specification ".
179 * @param[in] Value the width Value
181 * @return The bits for the register
220 /*----------------------------------------------------------------------------------------*/
222 * Access HT Link Control Register.
224 * @HtFeatMethod{::F_SET_HT_CONTROL_REGISTER_BITS}
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
230 * @note: This routine is called for CPUs as well as IO Devices! All comply to the
231 * "HyperTransport I/O Link Specification ".
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
240 SetHtControlRegisterBits (
251 ASSERT ((HiBit < 32) && (LoBit < 32) && (HiBit >= LoBit) && ((Reg.AddressValue & 0x3) == 0));
252 ASSERT ((HiBit < 8) || (LoBit > 9));
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);
258 mask = (UINT32)0xFFFFFFFF;
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);
268 /*----------------------------------------------------------------------------------------*/
270 * Set HT Frequency register for IO Devices
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
276 * @note This routine is called for IO Devices only!! All comply to the
277 * "HyperTransport I/O Link Specification ".
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
287 SetHtIoFrequencyRegisterBits (
298 ASSERT ((Hibit < 32) && (Lobit < 32) && (Hibit >= Lobit) && ((Reg.AddressValue & 0x3) == 0));
299 ASSERT ((Hibit < 12) || (Lobit > 14));
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);
305 Mask = (UINT32)0xFFFFFFFF;
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);
315 /*----------------------------------------------------------------------------------------*/
317 * Get Link features into system data structure.
319 * @HtFeatMethod{::F_GATHER_LINK_DATA}
321 * For all discovered Links, populate the port list with the frequency and width
322 * capabilities. Gather support data for:
325 * @param[in] State our global state, port list
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;
344 LinkBase = (*State->PortList)[i].Pointer;
345 if ((*State->PortList)[i].Link == 1) {
346 LinkBase.Address.Register += HTSLAVE_LINK01_OFFSET;
350 // Getting the Width is standard across device types
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);
356 LibAmdPciReadBits (Reg, 18, 16, &Bits, State->ConfigHandle);
357 (*State->PortList)[i].PrvWidthInCap = ConvertBitsToWidth ((UINT8)Bits);
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);
364 Reg.Address.Register += HTSLAVE_FREQ_REV_0_REG;
365 LibAmdPciReadBits (Reg, 31, 16, &Bits, State->ConfigHandle);
366 (*State->PortList)[i].PrvFrequencyCap = Bits;
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);
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).
378 Reg.Address.Register += HTSLAVE_FEATURECAP_REG;
380 LibAmdPciWriteBits (Reg, 5, 5, &Bits, State->ConfigHandle);
381 LibAmdPciReadBits (Reg, 5, 5, &Bits, State->ConfigHandle);
383 (*State->PortList)[i].ClumpingSupport = Bits;
385 (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE;
389 Reg.Address.Register = PCI_CONFIG_REVISION_REG08;
390 LibAmdPciReadBits ( LinkBase, 7, 0, &Bits, State->ConfigHandle);
391 Revision = (UINT8) Bits;
393 LinkBase.Address.Register = 0;
394 LibAmdPciRead (AccessWidth32, LinkBase, &Bits, State->ConfigHandle);
396 State->HtInterface->GetDeviceCapOverride ((*State->PortList)[i].NodeID,
397 (*State->PortList)[i].HostLink,
398 (*State->PortList)[i].HostDepth,
399 (*State->PortList)[i].Pointer,
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),
412 /*----------------------------------------------------------------------------------------*/
416 * @HtFeatMethod{::F_SELECT_OPTIMAL_WIDTH_AND_FREQUENCY}
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.
424 * @note no hardware state changes in this routine.
426 * @param[in,out] State Process and update portlist
429 SelectOptimalWidthAndFrequency (
430 IN OUT STATE_DATA *State
437 UINT32 CbPcbFreqLimit;
438 UINT8 CbPcbABDownstreamWidth;
439 UINT8 CbPcbBAUpstreamWidth;
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;
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,
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,
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;
474 Freq = LibAmdBitScanReverse (Temp);
475 (*State->PortList)[i].SelFrequency = Freq;
476 (*State->PortList)[i + 1].SelFrequency = Freq;
478 Temp = (*State->PortList)[i].PrvWidthOutCap;
479 if ((*State->PortList)[i + 1].PrvWidthInCap < Temp) {
480 Temp = (*State->PortList)[i + 1].PrvWidthInCap;
482 if (CbPcbABDownstreamWidth < Temp) {
483 Temp = CbPcbABDownstreamWidth;
485 (*State->PortList)[i].SelWidthOut = (UINT8)Temp;
486 (*State->PortList)[i + 1].SelWidthIn = (UINT8)Temp;
488 Temp = (*State->PortList)[i].PrvWidthInCap;
489 if ((*State->PortList)[i + 1].PrvWidthOutCap < Temp) {
490 Temp = (*State->PortList)[i + 1].PrvWidthOutCap;
492 if (CbPcbBAUpstreamWidth < Temp) {
493 Temp = CbPcbBAUpstreamWidth;
495 (*State->PortList)[i].SelWidthIn = (UINT8)Temp;
496 (*State->PortList)[i + 1].SelWidthOut = (UINT8)Temp;
498 // Calculate unit id clumping
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.
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;
525 (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE;
531 if ((*State->PortList)[i + 1].ClumpingSupport != HT_CLUMPING_PASSIVE) {
532 (*State->PortList)[i + 1].ClumpingSupport = (*State->PortList)[i].ClumpingSupport;
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;
552 /*----------------------------------------------------------------------------------------*/
554 * Change the hardware state for all Links according to the now optimized data in the
555 * port list data structure.
557 * @HtFeatMethod{::F_SET_LINK_DATA}
559 * @param[in] State our global state, port list
574 HTIDS_PORT_OVERRIDE_LIST PortOverrides;
576 PortOverrides = NULL;
578 for (i = 0; i < (State->TotalLinks * 2); i++) {
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);
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,
595 // IDS port override for CPUs and IO Devices
597 pf_HtIdsGetPortOverride ((BOOLEAN) ((i & 1) == 0), &(*State->PortList)[i], &(*State->PortList)[i + 1], &PortOverrides, State);
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;
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) {
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.
614 Reg.Address.Register = PCI_CONFIG_COMMAND_REG04;
615 LibAmdPciWriteBits (Reg, 8, 8, &Temp, State->ConfigHandle);
619 // Some IO devices don't work properly when setting widths, so write them in a single operation,
620 // rather than individually.
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);
627 Temp = (Widthin & 7) | ((Widthout & 7) << 4);
629 Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
630 State->HtFeatures->SetHtControlRegisterBits (Reg, 31, 24, &Temp, State);
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)));
637 if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) {
638 State->Nb->SetLinkFrequency (
639 (*State->PortList)[i].NodeID,
640 (*State->PortList)[i].Link,
645 ASSERT (Temp <= HT_FREQUENCY_2600M);
646 // Write the frequency setting
648 Reg.Address.Register += HTSLAVE_FREQ_REV_0_REG;
649 SetHtIoFrequencyRegisterBits (Reg, 11, 8, &Temp, State);
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
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).
661 if (Temp > HT_FREQUENCY_1000M) {
662 // Enabling features if gen 3
665 // Disabling features if gen 1
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),
677 State->ConfigHandle);
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.
683 NotifyWarningOptRequiredCapRetry ((*State->PortList)[i].NodeID,
684 (*State->PortList)[i].HostLink,
685 (*State->PortList)[i].HostDepth,
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);
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.
702 NotifyWarningOptRequiredCapGen3 ((*State->PortList)[i].NodeID,
703 (*State->PortList)[i].HostLink,
704 (*State->PortList)[i].HostDepth,
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,
722 if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_UNITID_CAPABILITY, &Reg, State)) {
723 Reg.Address.Register += HTUNIT_ENABLE_REG;
724 LibAmdPciWriteBits (Reg, 31, 0, &Bits, State->ConfigHandle);
726 // If we found one when gathering support, we have to find one now.
735 /*------------------------------------------------------------------------------------------*/
737 * Find a specific HT capability type.
739 * Search all the PCI Config space capabilities on any type of device for an
740 * HT capability of the specific subtype.
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
747 * @retval TRUE the capability was found
748 * @retval FALSE the capability was not found
751 DoesDeviceHaveHtSubtypeCap (
752 IN PCI_ADDR DevicePointer,
754 OUT PCI_ADDR *CapabilityBase,
763 UINT32 RegSubTypeMask;
765 // Set the PCI Config Space base and the match value.
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;
775 // Other HT capability subtype
776 RegSubType = ((UINT32) (CapSubType << 27) | (UINT32)8);
777 RegSubTypeMask = HT_CAP_SUBTYPE_MASK;
779 (*CapabilityBase).AddressValue = (UINT32)ILLEGAL_SBDFO;
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;
791 // Some other capability, keep looking
796 } while (!IsFound && !IsDone);
801 /*----------------------------------------------------------------------------------------*/
803 * Retry must be enabled on all coherent links if it is enabled on any coherent links.
805 * @HtFeatMethod{::F_SET_LINK_DATA}
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
810 * (Non-coherent links are independent.)
812 * @param[in,out] State global state, port frequency settings.
814 * @retval TRUE Fixup occurred, all coherent links HT1
815 * @retval FALSE No changes
818 IsCoherentRetryFixup (
824 UINT8 DetectedFrequencyState;
829 // detectedFrequencyState:
831 // 1 - HT1 Frequencies detected
832 // 2 - HT3 Frequencies detected
835 DetectedFrequencyState = 0;
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) {
843 // Set current state to indicate what link frequency we found first
844 if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) {
846 DetectedFrequencyState = 2;
849 DetectedFrequencyState = 1;
853 // If HT1 frequency detected, fail any HT3 frequency
854 if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) {
859 // If HT3 frequency detected, fail any HT1 frequency
860 if ((*State->PortList)[i].SelFrequency <= HT_FREQUENCY_1000M) {
868 // Don't need to keep checking after we find a mix.
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;
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;