/** * Get Link features into system data structure. * * @HtNbMethod{::F_GATHER_LINK_FEATURES} * * For a specific discovered CPU Link, populate the port list with the frequency * capabilities. Support for other link oriented capabilities, currently: * - Unit ID Clumping. Set to disabled. This doesn't mean the CPU doesn't support clumping, * it just means: * - The CPU doesn't clump its host unit ids, and * - We don't have to check as carefully in SetLinkData whether the port is an IO host link. * * @param[in,out] ThisPort The PortList structure entry for this link's port * @param[in] Interface Access to non-HT support functions. * @param[in] PlatformConfig Platform profile/build option config structure. * @param[in] Nb this northbridge */ VOID GatherLinkFeatures ( IN OUT PORT_DESCRIPTOR *ThisPort, IN HT_INTERFACE *Interface, IN PLATFORM_CONFIGURATION *PlatformConfig, IN NORTHBRIDGE *Nb ) { PCI_ADDR Reg; UINT32 Frequency; UINT32 ExtendedFrequency; Reg = ThisPort->Pointer; Reg.Address.Register += HTHOST_FREQ_REV_REG; LibAmdPciReadBits (Reg, 30, 16, &Frequency, Nb->ConfigHandle); Reg = ThisPort->Pointer; Reg.Address.Register += HTHOST_FREQ_EXTENSION; LibAmdPciReadBits (Reg, 15, 1, &ExtendedFrequency, Nb->ConfigHandle); ThisPort->PrvFrequencyCap = ((Frequency | (ExtendedFrequency << HT_FREQUENCY_2800M)) & Nb->NorthBridgeFreqMask (ThisPort->NodeID, Interface, PlatformConfig, Nb)); // Check for Internal link restriction not to run at 1000 MHz (but allow lower) if (IsPackageLinkInternal (Nb->GetPackageLink (ThisPort->NodeID, ThisPort->Link, Nb))) { ThisPort->PrvFrequencyCap &= ~(HT_FREQUENCY_LIMIT_1000M & ~HT_FREQUENCY_LIMIT_800M); } ThisPort->ClumpingSupport = HT_CLUMPING_DISABLE; }
/** * Fix (hopefully) exceptional conditions. * * @HtNbMethod{::F_HANDLE_SPECIAL_NODE_CASE}. * * Currently, this routine is implemented for all coherent HT families to check * vendor ID of coherent Node. If the vendor ID is 0x1022 then return FALSE, * or return TRUE. * * @param[in] Node The Node which need to be checked. * @param[in] Link The link to check for special conditions. * @param[in] State our global state. * @param[in] Nb this northbridge. * * @retval TRUE This node received special handling. * @retval FALSE This node was not handled specially, handle it normally. * */ BOOLEAN HandleSpecialNodeCase ( IN UINT8 Node, IN UINT8 Link, IN STATE_DATA *State, IN NORTHBRIDGE *Nb ) { BOOLEAN Result; PCI_ADDR Reg; UINT32 VendorID; Result = TRUE; Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), 0, 0); LibAmdPciReadBits (Reg, 15, 0, &VendorID, Nb->ConfigHandle); if (VendorID == 0x1022) { Result = FALSE; } return Result; }
/** * Return whether the current configuration exceeds the capability. * * @HtNbMethod{::F_IS_EXCEEDED_CAPABLE}. * * Get Node capability and update the minimum supported system capability. * * @param[in] Node the Node * @param[in] State sysMpCap (updated) and NodesDiscovered * @param[in] Nb this northbridge * * @retval TRUE system is not capable of current config. * @retval FALSE system is capable of current config. */ BOOLEAN Fam10IsExceededCapable ( IN UINT8 Node, IN STATE_DATA *State, IN NORTHBRIDGE *Nb ) { UINT32 Temp; UINT8 MaxNodes; PCI_ADDR Reg; ASSERT (Node < MAX_NODES); Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_03, REG_NB_CAPABILITY_3XE8); LibAmdPciReadBits (Reg, 18, 16, &Temp, Nb->ConfigHandle); if (Temp != 0) { MaxNodes = (UINT8) (1 << (~Temp & 0x3)); // That is, 1, 2, 4, or 8 } else { MaxNodes = 8; } if (State->SysMpCap > MaxNodes) { State->SysMpCap = MaxNodes; } // Note since sysMpCap is one based and NodesDiscovered is zero based, equal returns true // return ((BOOLEAN) (State->SysMpCap <= State->NodesDiscovered)); }
/** * Return the number of cores (1 based count) on Node. * * @HtNbMethod{::F_GET_NUM_CORES_ON_NODE} * * @param[in] Node the Node that will be examined * @param[in] Nb this northbridge * * @return the number of cores */ UINT8 Fam15Mod1xGetNumCoresOnNode ( IN UINT8 Node, IN NORTHBRIDGE *Nb ) { UINT32 Result; UINT32 Leveling; UINT32 Cores; UINT8 i; PCI_ADDR Reg; ASSERT ((Node < MAX_NODES)); // Read CmpCap Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_05, REG_NB_CAPABILITY_2_5X84); LibAmdPciReadBits (Reg, 7, 0, &Result, Nb->ConfigHandle); // Support Downcoring Cores = Result; Cores++; Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_03, REG_NB_DOWNCORE_3X190); LibAmdPciReadBits (Reg, 31, 0, &Leveling, Nb->ConfigHandle); for (i = 0; i < Cores; i++) { if ((Leveling & ((UINT32) 1 << i)) != 0) { Result--; } } return (UINT8) (Result + 1); }
/** * Read the Default Link * * @HtNbMethod{::F_READ_DEFAULT_LINK} * * Read the DefLnk (the source Link of the current packet) from Node. Since this code * is running on the BSP, this should be the Link pointing back towards the BSP. * * @param[in] Node the Node that will have its NodeID altered. * @param[in] Nb this northbridge * * @return The HyperTransport Link where the request to * read the default Link came from. */ UINT8 ReadDefaultLink ( IN UINT8 Node, IN NORTHBRIDGE *Nb ) { UINT32 DefaultLink; PCI_ADDR Reg; UINT32 Temp; DefaultLink = 0; Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_HTNB_FUNC_00, REG_LINK_INIT_CONTROL_0X6C); ASSERT ((Node < MAX_NODES)); LibAmdPciReadBits (Reg, 3, 2, &DefaultLink, Nb->ConfigHandle); LibAmdPciReadBits (Reg, 8, 8, &Temp, Nb->ConfigHandle); DefaultLink |= (Temp << 2); return (UINT8)DefaultLink; }
/** * Return the Link to the Southbridge * * @HtNbMethod{::F_READ_SB_LINK} * * @param[in] Nb this northbridge * * @return the Link to the southbridge */ UINT8 ReadSouthbridgeLink ( IN NORTHBRIDGE *Nb ) { UINT32 Temp; PCI_ADDR Reg; Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (0), MakePciBusFromNode (0), MakePciDeviceFromNode (0), CPU_HTNB_FUNC_00, REG_UNIT_ID_0X64); LibAmdPciReadBits (Reg, 10, 8, &Temp, Nb->ConfigHandle); return (UINT8)Temp; }
/** * Get the quad core compute unit status for this node. * * @TopoNbMethod{::PF_GET_QUADCORE_COMPUTE_UNITS} * * @param[in] Node The node for which we want the quad core status * @param[in] Nb Our Northbridge. * * @return The quad core compute unit status. */ UINT8 Fam16GetQuadcoreComputeUnits ( IN UINT8 Node, IN NORTHBRIDGE *Nb ) { UINT32 Quad; PCI_ADDR Reg; ASSERT ((Node < MAX_NODES)); Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_05, REG_NB_COMPUTE_UNIT_5X80); LibAmdPciReadBits (Reg, 27, 24, &Quad, Nb->ConfigHandle); return ((UINT8) Quad); }
/** * Get the dual core compute unit status for this node. * * @HtNbMethod{::PF_GET_DUALCORE_COMPUTE_UNITS} * * @param[in] Node The node for which we want the dual core status * @param[in] Nb Our Northbridge. * * @return The dual core compute unit status. */ UINT8 Fam15Mod1xGetDualcoreComputeUnits ( IN UINT8 Node, IN NORTHBRIDGE *Nb ) { UINT32 Dual; PCI_ADDR Reg; ASSERT ((Node < MAX_NODES)); Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_05, REG_NB_COMPUTE_UNIT_5X80); LibAmdPciReadBits (Reg, 17, 16, &Dual, Nb->ConfigHandle); return ((UINT8) Dual); }
/** * Construct a new northbridge. * * This routine encapsulates knowledge of how to tell significant differences between * families of supported northbridges and what routines can be used in common and * which are unique. A fully populated northbridge interface is provided by Nb. * * @param[in] Node create a northbridge interface for this Node. * @param[in] State global state * @param[out] Nb the caller's northbridge structure to initialize. */ VOID NewNorthBridge ( IN UINT8 Node, IN STATE_DATA *State, OUT NORTHBRIDGE *Nb ) { CPU_LOGICAL_ID LogicalId; UINT64 Match; UINT32 RawCpuId; PCI_ADDR Reg; NORTHBRIDGE **InitializerInstance; // Start with enough of the key to identify the northbridge interface Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC); LibAmdPciReadBits (Reg, 31, 0, &RawCpuId, State->ConfigHandle); IDS_HDT_CONSOLE (TOPO_TRACE, "AMD Processor at Node %d has raw CPUID=%x.\n", Node, RawCpuId); GetLogicalIdFromCpuid (RawCpuId, &LogicalId, State->ConfigHandle); Match = LogicalId.Family; // Test each Northbridge interface in turn looking for a match. // Use it to Init the Nb struct if a match is found. // ASSERT (OptionTopoConfiguration.TopoOptionFamilyNorthbridgeList != NULL); InitializerInstance = (NORTHBRIDGE **) (OptionTopoConfiguration.TopoOptionFamilyNorthbridgeList); while (*InitializerInstance != NULL) { if ((Match & (*InitializerInstance)->CompatibleKey) != 0) { LibAmdMemCopy ((VOID *)Nb, (VOID *)*InitializerInstance, (UINT32) sizeof (NORTHBRIDGE), State->ConfigHandle); break; } InitializerInstance++; } // There must be an available northbridge implementation. ASSERT (*InitializerInstance != NULL); // Set the config handle for passing to the library. Nb->ConfigHandle = State->ConfigHandle; }
/** * Read the token stored in the scratchpad register field. * * @HtNbMethod{::F_READ_TOKEN} * * Use the CPU core count as a scratch pad. * * @note The location used to store the token is arbitrary. The only requirement is * that the location warm resets to zero, and that using it will have no ill-effects * during HyperTransport initialization. * * @param[in] Node the Node that will be examined * @param[in] Nb this northbridge * * @return the Token read from the Node */ UINT8 ReadToken ( IN UINT8 Node, IN NORTHBRIDGE *Nb ) { UINT32 Temp; PCI_ADDR Reg; ASSERT ((Node < MAX_NODES)); // Use CpuCnt as a scratch register Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_HTNB_FUNC_00, REG_NODE_ID_0X60); LibAmdPciReadBits (Reg, 19, 16, &Temp, Nb->ConfigHandle); return (UINT8)Temp; }
/** * Make a compatibility key. * * @TopoNbMethod{::F_MAKE_KEY} * * Private routine to northbridge code. * Create a key which can be used to determine whether a Node is compatible with * the discovered configuration so far. Currently, that means the family, * extended family of the new Node are the same as the BSP's. Family specific * implementations can add whatever else is necessary. * * @param[in] Node the Node * @param[in] Nb this northbridge * * @return the key */ UINT64 MakeKey ( IN UINT8 Node, IN NORTHBRIDGE *Nb ) { CPU_LOGICAL_ID LogicalId; UINT32 RawCpuId; PCI_ADDR Reg; Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC); LibAmdPciReadBits (Reg, 31, 0, &RawCpuId, Nb->ConfigHandle); GetLogicalIdFromCpuid (RawCpuId, &LogicalId, Nb->ConfigHandle); return LogicalId.Family; }
/** * Return the number of cores (1 based count) on Node. * * @HtNbMethod{::F_GET_NUM_CORES_ON_NODE} * * @param[in] Node the Node that will be examined * @param[in] Nb this northbridge * * @return the number of cores */ UINT8 Fam12GetNumCoresOnNode ( IN UINT8 Node, IN NORTHBRIDGE *Nb ) { UINT32 Cores; PCI_ADDR Reg; ASSERT ((Node < MAX_NODES)); // Read CmpCap Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node), MakePciBusFromNode (Node), MakePciDeviceFromNode (Node), CPU_NB_FUNC_03, REG_NB_CAPABILITY_3XE8); LibAmdPciReadBits (Reg, 13, 12, &Cores, Nb->ConfigHandle); return (UINT8) (Cores + 1); }
/** * Returns the family specific properties of the cache, and its usage. * * @CpuServiceMethod{::F_CPU_GET_FAMILY_SPECIFIC_ARRAY}. * * @param[in] FamilySpecificServices The current Family Specific Services. * @param[out] CacheInfoPtr Points to the cache info properties on exit. * @param[out] NumberOfElements Will be one to indicate one entry. * @param[in] StdHeader Header for library and services. * */ VOID GetF15CacheInfo ( IN CPU_SPECIFIC_SERVICES *FamilySpecificServices, OUT CONST VOID **CacheInfoPtr, OUT UINT8 *NumberOfElements, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 Enabled; UINT32 DualCore; UINT32 Node; PCI_ADDR PciAddress; CPU_SPECIFIC_SERVICES *FamilyServices; AP_MAILBOXES ApMailboxes; CORE_PAIR_MAP *CorePairMap; AGESA_STATUS IgnoredStatus; if (!IsBsp (StdHeader, &IgnoredStatus)) { GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader); ASSERT (FamilyServices != NULL); FamilyServices->GetApMailboxFromHardware (FamilyServices, &ApMailboxes, StdHeader); Node = ApMailboxes.ApMailInfo.Fields.Node; // Since pre-heap, get compute unit status from hardware, using mailbox info. PciAddress.AddressValue = MAKE_SBDFO (0, 0, 24, 0, 0); PciAddress.Address.Device = PciAddress.Address.Device + Node; PciAddress.Address.Function = FUNC_5; PciAddress.Address.Register = COMPUTE_UNIT_STATUS; LibAmdPciReadBits (PciAddress, 3, 0, &Enabled, StdHeader); LibAmdPciReadBits (PciAddress, 19, 16, &DualCore, StdHeader); // Find the core to compute unit mapping for this node. CorePairMap = FamilyServices->CorePairMap; if ((Enabled != 0) && (CorePairMap != NULL)) { while (CorePairMap->Enabled != 0xFF) { if ((Enabled == CorePairMap->Enabled) && (DualCore == CorePairMap->DualCore)) { break; } CorePairMap++; } // The assert is for finding a processor configured in a way the core pair map doesn't support. ASSERT (CorePairMap->Enabled != 0xFF); switch (CorePairMap->Mapping) { case AllCoresMapping: // No cores are sharing a compute unit *CacheInfoPtr = &CpuF15CacheInfo; break; case EvenCoresMapping: // Cores are paired into compute units *CacheInfoPtr = &CpuF15CacheInfoCP; break; default: ASSERT (FALSE); } } } else { // the BSC is always just the first slice, we could return either one. Return the non for safest. *CacheInfoPtr = &CpuF15CacheInfo; } *NumberOfElements = 1; }
/** * Get Link features into system data structure. * * @HtFeatMethod{::F_GATHER_LINK_DATA} * * For all discovered Links, populate the port list with the frequency and width * capabilities. Gather support data for: * - Unit ID Clumping * * @param[in] State our global state, port list */ VOID GatherLinkData ( IN STATE_DATA *State ) { UINT8 i; PCI_ADDR LinkBase; PCI_ADDR Reg; UINT32 Bits; UINT8 Revision; // Get the capability base for whatever device type the link port is on for (i = 0; i < (State->TotalLinks * 2); i++) { if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) { LinkBase = State->Nb->MakeLinkBase ((*State->PortList)[i].NodeID, (*State->PortList)[i].Link, State->Nb); (*State->PortList)[i].Pointer = LinkBase; } else { LinkBase = (*State->PortList)[i].Pointer; if ((*State->PortList)[i].Link == 1) { LinkBase.Address.Register += HTSLAVE_LINK01_OFFSET; } } // Getting the Width is standard across device types Reg = LinkBase; Reg.Address.Register += HTSLAVE_LINK_CONTROL_0_REG; LibAmdPciReadBits (Reg, 22, 20, &Bits, State->ConfigHandle); (*State->PortList)[i].PrvWidthOutCap = ConvertBitsToWidth ((UINT8)Bits); LibAmdPciReadBits (Reg, 18, 16, &Bits, State->ConfigHandle); (*State->PortList)[i].PrvWidthInCap = ConvertBitsToWidth ((UINT8)Bits); // Get Frequency and other device type specific features if ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) { State->Nb->GatherLinkFeatures (&(*State->PortList)[i], State->HtInterface, State->PlatformConfiguration, State->Nb); } else { Reg = LinkBase; Reg.Address.Register += HTSLAVE_FREQ_REV_0_REG; LibAmdPciReadBits (Reg, 31, 16, &Bits, State->ConfigHandle); (*State->PortList)[i].PrvFrequencyCap = Bits; // Unit ID Clumping Support if (State->IsUsingUnitIdClumping) { if (DoesDeviceHaveHtSubtypeCap (LinkBase, HT_UNITID_CAPABILITY, &Reg, State)) { Reg.Address.Register += HTUNIT_SUPPORT_REG; LibAmdPciReadBits (Reg, 31, 0, &Bits, State->ConfigHandle); } else { // Not there, that's ok, we don't know that it should have one. // Check for Passive support. (Bit 0 won't be set if full support is implemented, // so we can use it to indicate passive support in our portlist struct). Reg = LinkBase; Reg.Address.Register += HTSLAVE_FEATURECAP_REG; Bits = 1; LibAmdPciWriteBits (Reg, 5, 5, &Bits, State->ConfigHandle); LibAmdPciReadBits (Reg, 5, 5, &Bits, State->ConfigHandle); } (*State->PortList)[i].ClumpingSupport = Bits; } else { (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE; } Reg = LinkBase; Reg.Address.Register = PCI_CONFIG_REVISION_REG08; LibAmdPciReadBits ( LinkBase, 7, 0, &Bits, State->ConfigHandle); Revision = (UINT8) Bits; LinkBase.Address.Register = 0; LibAmdPciRead (AccessWidth32, LinkBase, &Bits, State->ConfigHandle); State->HtInterface->GetDeviceCapOverride ((*State->PortList)[i].NodeID, (*State->PortList)[i].HostLink, (*State->PortList)[i].HostDepth, (*State->PortList)[i].Pointer, Bits, Revision, (*State->PortList)[i].Link, &((*State->PortList)[i].PrvWidthInCap), &((*State->PortList)[i].PrvWidthOutCap), &((*State->PortList)[i].PrvFrequencyCap), &((*State->PortList)[i].ClumpingSupport), State); } } }