diff options
Diffstat (limited to 'src/northbridge/amd/amdht/h3finit.c')
-rw-r--r-- | src/northbridge/amd/amdht/h3finit.c | 1879 |
1 files changed, 0 insertions, 1879 deletions
diff --git a/src/northbridge/amd/amdht/h3finit.c b/src/northbridge/amd/amdht/h3finit.c deleted file mode 100644 index cda0a28cef..0000000000 --- a/src/northbridge/amd/amdht/h3finit.c +++ /dev/null @@ -1,1879 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * Copyright (C) 2007 Advanced Micro Devices, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - *---------------------------------------------------------------------------- - * MODULES USED - * - *---------------------------------------------------------------------------- - */ - -#include "h3finit.h" -#include "h3ffeat.h" -#include "h3ncmn.h" -#include "h3gtopo.h" -#include "AsPsNb.h" - -#include <arch/cpu.h> -#include <device/pci.h> -#include <device/pci_ops.h> -#include <console/console.h> -#include <cpu/x86/lapic_def.h> -#include <cpu/amd/msr.h> -#include <device/pci_def.h> -#include <northbridge/amd/amdfam10/raminit.h> -#include <northbridge/amd/amdfam10/amdfam10.h> -#include <types.h> - -/*---------------------------------------------------------------------------- - * DEFINITIONS AND MACROS - * - *---------------------------------------------------------------------------- - */ - -#define NVRAM_LIMIT_HT_SPEED_200 0x12 -#define NVRAM_LIMIT_HT_SPEED_300 0x11 -#define NVRAM_LIMIT_HT_SPEED_400 0x10 -#define NVRAM_LIMIT_HT_SPEED_500 0xf -#define NVRAM_LIMIT_HT_SPEED_600 0xe -#define NVRAM_LIMIT_HT_SPEED_800 0xd -#define NVRAM_LIMIT_HT_SPEED_1000 0xc -#define NVRAM_LIMIT_HT_SPEED_1200 0xb -#define NVRAM_LIMIT_HT_SPEED_1400 0xa -#define NVRAM_LIMIT_HT_SPEED_1600 0x9 -#define NVRAM_LIMIT_HT_SPEED_1800 0x8 -#define NVRAM_LIMIT_HT_SPEED_2000 0x7 -#define NVRAM_LIMIT_HT_SPEED_2200 0x6 -#define NVRAM_LIMIT_HT_SPEED_2400 0x5 -#define NVRAM_LIMIT_HT_SPEED_2600 0x4 -#define NVRAM_LIMIT_HT_SPEED_2800 0x3 -#define NVRAM_LIMIT_HT_SPEED_3000 0x2 -#define NVRAM_LIMIT_HT_SPEED_3200 0x1 -#define NVRAM_LIMIT_HT_SPEED_AUTO 0x0 - -static const uint32_t ht_speed_limit[20] = - {0xFFFFF, 0xFFFFF, 0x7FFFF, 0x3FFFF, - 0x0FFFF, 0x07FFF, 0x03FFF, 0x01FFF, - 0x00FFF, 0x007FF, 0x003FF, 0x001FF, - 0x000FF, 0x0007F, 0x0003F, 0x0001F, - 0x0000F, 0x00007, 0x00003, 0x00001}; - -static const struct ht_speed_limit_map_t { - uint16_t mhz; - uint8_t nvram; -} ht_speed_limit_map[] = { - {0, NVRAM_LIMIT_HT_SPEED_AUTO}, - {200, NVRAM_LIMIT_HT_SPEED_200}, - {300, NVRAM_LIMIT_HT_SPEED_300}, - {400, NVRAM_LIMIT_HT_SPEED_400}, - {500, NVRAM_LIMIT_HT_SPEED_500}, - {600, NVRAM_LIMIT_HT_SPEED_600}, - {800, NVRAM_LIMIT_HT_SPEED_800}, - {1000, NVRAM_LIMIT_HT_SPEED_1000}, - {1200, NVRAM_LIMIT_HT_SPEED_1200}, - {1400, NVRAM_LIMIT_HT_SPEED_1400}, - {1600, NVRAM_LIMIT_HT_SPEED_1600}, - {1800, NVRAM_LIMIT_HT_SPEED_1800}, - {2000, NVRAM_LIMIT_HT_SPEED_2000}, - {2200, NVRAM_LIMIT_HT_SPEED_2200}, - {2400, NVRAM_LIMIT_HT_SPEED_2400}, - {2600, NVRAM_LIMIT_HT_SPEED_2600}, - {2800, NVRAM_LIMIT_HT_SPEED_2800}, - {3000, NVRAM_LIMIT_HT_SPEED_3000}, - {3200, NVRAM_LIMIT_HT_SPEED_3200}, -}; - -static const uint32_t ht_speed_mhz_to_hw(uint16_t mhz) -{ - size_t i; - for (i = 0; i < ARRAY_SIZE(ht_speed_limit_map); i++) - if (ht_speed_limit_map[i].mhz == mhz) - return ht_speed_limit[ht_speed_limit_map[i].nvram]; - - printk(BIOS_WARNING, - "WARNING: Invalid HT link limit frequency %d specified, ignoring...\n", - mhz); - return ht_speed_limit[NVRAM_LIMIT_HT_SPEED_AUTO]; -} - -/*---------------------------------------------------------------------------- - * TYPEDEFS AND STRUCTURES - * - *---------------------------------------------------------------------------- - */ - -/*---------------------------------------------------------------------------- - * PROTOTYPES OF LOCAL FUNCTIONS - * - *---------------------------------------------------------------------------- - */ - -/*---------------------------------------------------------------------------- - * EXPORTED FUNCTIONS - * - *---------------------------------------------------------------------------- - */ - -/*---------------------------------------------------------------------------- - * LOCAL FUNCTIONS - * - *---------------------------------------------------------------------------- - */ -#ifndef HT_BUILD_NC_ONLY -/* - ************************************************************************** - * Routing table decompressor - ************************************************************************** - */ - -/* - ************************************************************************** - * Graph Support routines - * These routines provide support for dealing with the graph representation - * of the topologies, along with the routing table information for that topology. - * The routing information is compressed and these routines currently decompress - * 'on the fly'. A graph is represented as a set of routes. All the edges in the - * graph are routes; a direct route from node i to node j exists in the graph IFF - * there is an edge directly connecting node i to node j. All other routes designate - * the edge which the route to that node initially takes, by designating a node - * to which a direct connection exists. That is, the route to non-adjacent node j - * from node i specifies node k where node i directly connects to node k. - * - * - * pseudo definition of compressed graph: - * typedef struct - * { - * BIT broadcast[8]; - * uint4 responseRoute; - * uint4 requestRoute; - * } sRoute; - * typedef struct - * { - * u8 size; - * sRoute graph[size][size]; - * } sGraph; - * - ************************************************************************** - */ - -/*---------------------------------------------------------------------------------------- - * u8 - * graphHowManyNodes(u8 *graph) - * - * Description: - * Returns the number of nodes in the compressed graph - * - * Parameters: - * @param[in] graph = a compressed graph - * @param[out] results = the number of nodes in the graph - * --------------------------------------------------------------------------------------- - */ -static u8 graphHowManyNodes(u8 *graph) -{ - return graph[0]; -} - -/*---------------------------------------------------------------------------------------- - * BOOL - * graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB) - * - * Description: - * Returns true if NodeA is directly connected to NodeB, false otherwise - * (if NodeA == NodeB also returns false) - * Relies on rule that directly connected nodes always route requests directly. - * - * Parameters: - * @param[in] graph = the graph to examine - * @param[in] nodeA = the node number of the first node - * @param[in] nodeB = the node number of the second node - * @param[out] results = true if nodeA connects to nodeB false if not - * --------------------------------------------------------------------------------------- - */ -static BOOL graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB) -{ - u8 size = graph[0]; - ASSERT(size <= MAX_NODES); - ASSERT((nodeA < size) && (nodeB < size)); - return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F) == nodeB; -} - -/*---------------------------------------------------------------------------------------- - * u8 - * graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB) - * - * Description: - * Returns the graph node used by nodeA to route responses targeted at nodeB. - * This will be a node directly connected to nodeA (possibly nodeB itself), - * or "Route to Self" if nodeA and nodeB are the same node. - * Note that all node numbers are abstract node numbers of the topology graph, - * it is the responsibility of the caller to apply any permutation needed. - * - * Parameters: - * @param[in] u8 graph = the graph to examine - * @param[in] u8 nodeA = the node number of the first node - * @param[in] u8 nodeB = the node number of the second node - * @param[out] u8 results = The response route node - * --------------------------------------------------------------------------------------- - */ -static u8 graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB) -{ - u8 size = graph[0]; - ASSERT(size <= MAX_NODES); - ASSERT((nodeA < size) && (nodeB < size)); - return (graph[1+(nodeA*size+nodeB)*2+1] & 0xF0)>>4; -} - -/*---------------------------------------------------------------------------------------- - * u8 - * graphGetReq(u8 *graph, u8 nodeA, u8 nodeB) - * - * Description: - * Returns the graph node used by nodeA to route requests targeted at nodeB. - * This will be a node directly connected to nodeA (possibly nodeB itself), - * or "Route to Self" if nodeA and nodeB are the same node. - * Note that all node numbers are abstract node numbers of the topology graph, - * it is the responsibility of the caller to apply any permutation needed. - * - * Parameters: - * @param[in] graph = the graph to examine - * @param[in] nodeA = the node number of the first node - * @param[in] nodeB = the node number of the second node - * @param[out] results = The request route node - * --------------------------------------------------------------------------------------- - */ -static u8 graphGetReq(u8 *graph, u8 nodeA, u8 nodeB) -{ - u8 size = graph[0]; - ASSERT(size <= MAX_NODES); - ASSERT((nodeA < size) && (nodeB < size)); - return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F); -} - -/*---------------------------------------------------------------------------------------- - * u8 - * graphGetBc(u8 *graph, u8 nodeA, u8 nodeB) - * - * Description: - * Returns a bit vector of nodes that nodeA should forward a broadcast from - * nodeB towards - * - * Parameters: - * @param[in] graph = the graph to examine - * @param[in] nodeA = the node number of the first node - * @param[in] nodeB = the node number of the second node - * OU results = the broadcast routes for nodeA from nodeB - * --------------------------------------------------------------------------------------- - */ -static u8 graphGetBc(u8 *graph, u8 nodeA, u8 nodeB) -{ - u8 size = graph[0]; - ASSERT(size <= MAX_NODES); - ASSERT((nodeA < size) && (nodeB < size)); - return graph[1+(nodeA*size+nodeB)*2]; -} - - -/*************************************************************************** - *** GENERIC HYPERTRANSPORT DISCOVERY CODE *** - ***************************************************************************/ - -/*---------------------------------------------------------------------------------------- - * void - * routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat) - * - * Description: - * Ensure a request / response route from target node to bsp. Since target node is - * always a predecessor of actual target node, each node gets a route to actual target - * on the link that goes to target. The routing produced by this routine is adequate - * for config access during discovery, but NOT for coherency. - * - * Parameters: - * @param[in] u8 targetNode = the path to actual target goes through target - * @param[in] u8 actualTarget = the ultimate target being routed to - * @param[in] sMainData* pDat = our global state, port config info - * --------------------------------------------------------------------------------------- - */ -static void routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat) -{ - u8 predecessorNode, predecessorLink, currentPair; - - if (targetNode == 0) - return; /* BSP has no predecessor, stop */ - - /* Search for the link that connects targetNode to its predecessor */ - currentPair = 0; - while (pDat->PortList[currentPair*2+1].NodeID != targetNode) - { - currentPair++; - ASSERT(currentPair < pDat->TotalLinks); - } - - predecessorNode = pDat->PortList[currentPair*2].NodeID; - predecessorLink = pDat->PortList[currentPair*2].Link; - - /* Recursively call self to ensure the route from the BSP to the Predecessor */ - /* Node is established */ - routeFromBSP(predecessorNode, actualTarget, pDat); - - pDat->nb->writeRoutingTable(predecessorNode, actualTarget, predecessorLink, pDat->nb); -} - -/*---------------------------------------------------------------------------*/ - -/** - * u8 - * convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat) - * - * Description: - * Return the link on source node which connects to target node - * - * Parameters: - * @param[in] srcNode = the source node - * @param[in] targetNode = the target node to find the link to - * @param[in] pDat = our global state - * @return the link on source which connects to target - * - */ -static u8 convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat) -{ - u8 targetlink = INVALID_LINK; - u8 k; - - for (k = 0; k < pDat->TotalLinks*2; k += 2) - { - if ((pDat->PortList[k+0].NodeID == srcNode) && (pDat->PortList[k+1].NodeID == targetNode)) - { - targetlink = pDat->PortList[k+0].Link; - break; - } - else if ((pDat->PortList[k+1].NodeID == srcNode) && (pDat->PortList[k+0].NodeID == targetNode)) - { - targetlink = pDat->PortList[k+1].Link; - break; - } - } - ASSERT(targetlink != INVALID_LINK); - - return targetlink; -} - - -/*---------------------------------------------------------------------------------------- - * void - * htDiscoveryFloodFill(sMainData *pDat) - * - * Description: - * Discover all coherent devices in the system, initializing some basics like node IDs - * and total nodes found in the process. As we go we also build a representation of the - * discovered system which we will use later to program the routing tables. During this - * step, the routing is via default link back to BSP and to each new node on the link it - * was discovered on (no coherency is active yet). - * - * Parameters: - * @param[in] sMainData* pDat = our global state - * --------------------------------------------------------------------------------------- - */ -static void htDiscoveryFloodFill(sMainData *pDat) -{ - uint8_t currentNode = 0; - uint8_t currentLink; - uint8_t currentLinkID; - - /* NOTE - * Each node inside a dual node (socket G34) processor must share - * an adjacent node ID. Alter the link scan order such that the - * other internal node is always scanned first... - */ - uint8_t currentLinkScanOrder_Default[8] = {0, 1, 2, 3, 4, 5, 6, 7}; - uint8_t currentLinkScanOrder_G34_Fam10[8] = {1, 0, 2, 3, 4, 5, 6, 7}; - uint8_t currentLinkScanOrder_G34_Fam15[8] = {2, 0, 1, 3, 4, 5, 6, 7}; - - uint8_t fam15h = 0; - uint8_t rev_gte_d = 0; - uint8_t dual_node = 0; - uint32_t f3xe8; - uint32_t family; - uint32_t model; - - f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8); - - family = model = cpuid_eax(0x80000001); - model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4); - family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8); - - if (family >= 0x6f) { - /* Family 15h or later */ - fam15h = 1; - } - - if ((model >= 0x8) || fam15h) - /* Revision D or later */ - rev_gte_d = 1; - - if (rev_gte_d) - /* Check for dual node capability */ - if (f3xe8 & 0x20000000) - dual_node = 1; - - /* Entries are always added in pairs, the even indices are the 'source' - * side closest to the BSP, the odd indices are the 'destination' side - */ - while (currentNode <= pDat->NodesDiscovered) - { - u32 temp; - - if (currentNode != 0) - { - /* Set path from BSP to currentNode */ - routeFromBSP(currentNode, currentNode, pDat); - - /* Set path from BSP to currentNode for currentNode+1 if - * currentNode+1 != MAX_NODES - */ - if (currentNode+1 != MAX_NODES) - routeFromBSP(currentNode, currentNode+1, pDat); - - /* Configure currentNode to route traffic to the BSP through its - * default link - */ - pDat->nb->writeRoutingTable(currentNode, 0, pDat->nb->readDefLnk(currentNode, pDat->nb), pDat->nb); - } - - /* Set currentNode's NodeID field to currentNode */ - pDat->nb->writeNodeID(currentNode, currentNode, pDat->nb); - - /* Enable routing tables on currentNode */ - pDat->nb->enableRoutingTables(currentNode, pDat->nb); - - for (currentLinkID = 0; currentLinkID < pDat->nb->maxLinks; currentLinkID++) - { - BOOL linkfound; - u8 token; - - if (currentLinkID < 8) { - if (dual_node) { - if (fam15h) - currentLink = currentLinkScanOrder_G34_Fam15[currentLinkID]; - else - currentLink = currentLinkScanOrder_G34_Fam10[currentLinkID]; - } else { - currentLink = currentLinkScanOrder_Default[currentLinkID]; - } - } else { - currentLink = currentLinkID; - } - - if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(currentNode, currentLink)) - continue; - - if (pDat->nb->readTrueLinkFailStatus(currentNode, currentLink, pDat, pDat->nb)) - continue; - - /* Make sure that the link is connected, coherent, and ready */ - if (!pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb)) - continue; - - - /* Test to see if the currentLink has already been explored */ - linkfound = FALSE; - for (temp = 0; temp < pDat->TotalLinks; temp++) - { - if ((pDat->PortList[temp*2+1].NodeID == currentNode) && - (pDat->PortList[temp*2+1].Link == currentLink)) - { - linkfound = TRUE; - break; - } - } - if (linkfound) - { - /* We had already expored this link */ - continue; - } - - if (pDat->nb->handleSpecialLinkCase(currentNode, currentLink, pDat, pDat->nb)) - { - continue; - } - - /* Modify currentNode's routing table to use currentLink to send - * traffic to currentNode+1 - */ - pDat->nb->writeRoutingTable(currentNode, currentNode+1, currentLink, pDat->nb); - - /* Check the northbridge of the node we just found, to make sure it is compatible - * before doing anything else to it. - */ - if (!pDat->nb->isCompatible(currentNode+1, pDat->nb)) - { - u8 nodeToKill; - - /* Notify BIOS of event (while variables are still the same) */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventCohFamilyFeud evt; - evt.eSize = sizeof(sHtEventCohFamilyFeud); - evt.node = currentNode; - evt.link = currentLink; - evt.totalNodes = pDat->NodesDiscovered; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, - HT_EVENT_COH_FAMILY_FEUD, - (u8 *)&evt); - } - - /* If node is not compatible, force boot to 1P - * If they are not compatible stop cHT init and: - * 1. Disable all cHT links on the BSP - * 2. Configure the BSP routing tables as a UP. - * 3. Notify main BIOS. - */ - pDat->NodesDiscovered = 0; - currentNode = 0; - pDat->TotalLinks = 0; - /* Abandon our coherent link data structure. At this point there may - * be coherent links on the BSP that are not yet in the portList, and - * we have to turn them off anyway. So depend on the hardware to tell us. - */ - for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++) - { - /* Stop all links which are connected, coherent, and ready */ - if (pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb)) - pDat->nb->stopLink(currentNode, currentLink, pDat->nb); - } - - for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++) - { - pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb); - } - - /* End Coherent Discovery */ - STOP_HERE; - break; - } - - /* Read token from Current+1 */ - token = pDat->nb->readToken(currentNode+1, pDat->nb); - ASSERT(token <= pDat->NodesDiscovered); - if (token == 0) - { - pDat->NodesDiscovered++; - ASSERT(pDat->NodesDiscovered < pDat->nb->maxNodes); - /* Check the capability of northbridges against the currently known configuration */ - if (!pDat->nb->isCapable(currentNode+1, pDat, pDat->nb)) - { - u8 nodeToKill; - - /* Notify BIOS of event */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventCohMpCapMismatch evt; - evt.eSize = sizeof(sHtEventCohMpCapMismatch); - evt.node = currentNode; - evt.link = currentLink; - evt.sysMpCap = pDat->sysMpCap; - evt.totalNodes = pDat->NodesDiscovered; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, - HT_EVENT_COH_MPCAP_MISMATCH, - (u8 *)&evt); - } - - pDat->NodesDiscovered = 0; - currentNode = 0; - pDat->TotalLinks = 0; - - for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++) - { - pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb); - } - - /* End Coherent Discovery */ - STOP_HERE; - break; - } - - token = pDat->NodesDiscovered; - pDat->nb->writeToken(currentNode+1, token, pDat->nb); - /* Inform that we have discovered a node, so that logical id to - * socket mapping info can be recorded. - */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventCohNodeDiscovered evt; - evt.eSize = sizeof(sHtEventCohNodeDiscovered); - evt.node = currentNode; - evt.link = currentLink; - evt.newNode = token; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO, - HT_EVENT_COH_NODE_DISCOVERED, - (u8 *)&evt); - } - } - - if (pDat->TotalLinks == MAX_PLATFORM_LINKS) - { - /* - * Exceeded our capacity to describe all coherent links found in the system. - * Error strategy: - * Auto recovery is not possible because data space is already all used. - * If the callback is not implemented or returns we will continue to initialize - * the fabric we are capable of representing, adding no more nodes or links. - * This should yield a bootable topology, but likely not the one intended. - * We cannot continue discovery, there may not be any way to route a new - * node back to the BSP if we can't add links to our representation of the system. - */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventCohLinkExceed evt; - evt.eSize = sizeof(sHtEventCohLinkExceed); - evt.node = currentNode; - evt.link = currentLink; - evt.targetNode = token; - evt.totalNodes = pDat->NodesDiscovered; - evt.maxLinks = pDat->nb->maxLinks; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, - HT_EVENT_COH_LINK_EXCEED, - (u8 *)&evt); - } - /* Force link and node loops to halt */ - STOP_HERE; - currentNode = pDat->NodesDiscovered; - break; - } - - pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU; - pDat->PortList[pDat->TotalLinks*2].Link = currentLink; - pDat->PortList[pDat->TotalLinks*2].NodeID = currentNode; - - pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_CPU; - pDat->PortList[pDat->TotalLinks*2+1].Link = pDat->nb->readDefLnk(currentNode+1, pDat->nb); - pDat->PortList[pDat->TotalLinks*2+1].NodeID = token; - - pDat->TotalLinks++; - - if (!pDat->sysMatrix[currentNode][token]) - { - pDat->sysDegree[currentNode]++; - pDat->sysDegree[token]++; - pDat->sysMatrix[currentNode][token] = TRUE; - pDat->sysMatrix[token][currentNode] = TRUE; - } - } - currentNode++; - } -} - - -/*************************************************************************** - *** ISOMORPHISM BASED ROUTING TABLE GENERATION CODE *** - ***************************************************************************/ - -/*---------------------------------------------------------------------------------------- - * BOOL - * isoMorph(u8 i, sMainData *pDat) - * - * Description: - * Is graphA isomorphic to graphB? - * if this function returns true, then Perm will contain the permutation - * required to transform graphB into graphA. - * We also use the degree of each node, that is the number of connections it has, to - * speed up rejection of non-isomorphic graphs (if there is a node in graphA with n - * connections, there must be at least one unmatched in graphB with n connections). - * - * Parameters: - * @param[in] u8 i = the discovered node which we are trying to match - * with a permutation the topology - * @param[in]/@param[out] sMainData* pDat = our global state, degree and adjacency matrix, - * output a permutation if successful - * @param[out] BOOL results = the graphs are (or are not) isomorphic - * --------------------------------------------------------------------------------------- - */ -static BOOL isoMorph(u8 i, sMainData *pDat) -{ - u8 j, k; - u8 nodecnt; - - /* We have only been called if nodecnt == pSelected->size ! */ - nodecnt = pDat->NodesDiscovered+1; - - if (i != nodecnt) - { - /* Keep building the permutation */ - for (j = 0; j < nodecnt; j++) - { - /* Make sure the degree matches */ - if (pDat->sysDegree[i] != pDat->dbDegree[j]) - continue; - - /* Make sure that j hasn't been used yet (ought to use a "used" */ - /* array instead, might be faster) */ - for (k = 0; k < i; k++) - { - if (pDat->Perm[k] == j) - break; - } - if (k != i) - continue; - pDat->Perm[i] = j; - if (isoMorph(i+1, pDat)) - return TRUE; - } - return FALSE; - } else { - /* Test to see if the permutation is isomorphic */ - for (j = 0; j < nodecnt; j++) - { - for (k = 0; k < nodecnt; k++) - { - if (pDat->sysMatrix[j][k] != - pDat->dbMatrix[pDat->Perm[j]][pDat->Perm[k]]) - return FALSE; - } - } - return TRUE; - } -} - - -/*---------------------------------------------------------------------------------------- - * void - * lookupComputeAndLoadRoutingTables(sMainData *pDat) - * - * Description: - * Using the description of the fabric topology we discovered, try to find a match - * among the supported topologies. A supported topology description matches - * the discovered fabric if the nodes can be matched in such a way that all the nodes connected - * in one set are exactly the nodes connected in the other (formally, that the graphs are - * isomorphic). Which links are used is not really important to matching. If the graphs - * match, then there is a permutation of one that translates the node positions and linkages - * to the other. - * - * In order to make the isomorphism test efficient, we test for matched number of nodes - * (a 4 node fabric is not isomorphic to a 2 node topology), and provide degrees of nodes - * to the isomorphism test. - * - * The generic routing table solution for any topology is predetermined and represented - * as part of the topology. The permutation we computed tells us how to interpret the - * routing onto the fabric we discovered. We do this working backward from the last - * node discovered to the BSP, writing the routing tables as we go. - * - * Parameters: - * @param[in] sMainData* pDat = our global state, the discovered fabric, - * @param[out] degree matrix, permutation - * --------------------------------------------------------------------------------------- - */ -static void lookupComputeAndLoadRoutingTables(sMainData *pDat) -{ - u8 **pTopologyList; - u8 *pSelected; - - int i, j, k, size; - - size = pDat->NodesDiscovered + 1; - /* Use the provided topology list or the internal, default one. */ - pTopologyList = pDat->HtBlock->topolist; - if (pTopologyList == NULL) - { - getAmdTopolist(&pTopologyList); - } - - pSelected = *pTopologyList; - while (pSelected != NULL) - { - if (graphHowManyNodes(pSelected) == size) - { - /* Build Degree vector and Adjency Matrix for this entry */ - for (i = 0; i < size; i++) - { - pDat->dbDegree[i] = 0; - for (j = 0; j < size; j++) - { - if (graphIsAdjacent(pSelected, i, j)) - { - pDat->dbMatrix[i][j] = 1; - pDat->dbDegree[i]++; - } - else - { - pDat->dbMatrix[i][j] = 0; - } - } - } - if (isoMorph(0, pDat)) - break; /* A matching topology was found */ - } - - pTopologyList++; - pSelected = *pTopologyList; - } - - if (pSelected != NULL) - { - /* Compute the reverse Permutation */ - for (i = 0; i < size; i++) - { - pDat->ReversePerm[pDat->Perm[i]] = i; - } - - /* Start with the last discovered node, and move towards the BSP */ - for (i = size-1; i >= 0; i--) - { - for (j = 0; j < size; j++) - { - u8 ReqTargetLink, RspTargetLink; - u8 ReqTargetNode, RspTargetNode; - - u8 AbstractBcTargetNodes = graphGetBc(pSelected, pDat->Perm[i], pDat->Perm[j]); - u32 BcTargetLinks = 0; - - for (k = 0; k < MAX_NODES; k++) - { - if (AbstractBcTargetNodes & ((u32)1<<k)) - { - BcTargetLinks |= (u32)1 << convertNodeToLink(i, pDat->ReversePerm[k], pDat); - } - } - - if (i == j) - { - ReqTargetLink = ROUTETOSELF; - RspTargetLink = ROUTETOSELF; - } - else - { - ReqTargetNode = graphGetReq(pSelected, pDat->Perm[i], pDat->Perm[j]); - ReqTargetLink = convertNodeToLink(i, pDat->ReversePerm[ReqTargetNode], pDat); - - RspTargetNode = graphGetRsp(pSelected, pDat->Perm[i], pDat->Perm[j]); - RspTargetLink = convertNodeToLink(i, pDat->ReversePerm[RspTargetNode], pDat); - } - - pDat->nb->writeFullRoutingTable(i, j, ReqTargetLink, RspTargetLink, BcTargetLinks, pDat->nb); - } - /* Clean up discovery 'footprint' that otherwise remains in the routing table. It didn't hurt - * anything, but might cause confusion during debug and validation. Do this by setting the - * route back to all self routes. Since it's the node that would be one more than actually installed, - * this only applies if less than maxNodes were found. - */ - if (size < pDat->nb->maxNodes) - { - pDat->nb->writeFullRoutingTable(i, size, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb); - } - } - - } - else - { - /* - * No Matching Topology was found - * Error Strategy: - * Auto recovery doesn't seem likely, Force boot as 1P. - * For reporting, logging, provide number of nodes - * If not implemented or returns, boot as BSP uniprocessor. - */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventCohNoTopology evt; - evt.eSize = sizeof(sHtEventCohNoTopology); - evt.totalNodes = pDat->NodesDiscovered; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, - HT_EVENT_COH_NO_TOPOLOGY, - (u8 *)&evt); - } - STOP_HERE; - /* Force 1P */ - pDat->NodesDiscovered = 0; - pDat->TotalLinks = 0; - pDat->nb->enableRoutingTables(0, pDat->nb); - } -} -#endif /* HT_BUILD_NC_ONLY */ - - -/*---------------------------------------------------------------------------------------- - * void - * finializeCoherentInit(sMainData *pDat) - * - * Description: - * Find the total number of cores and update the number of nodes and cores in all cpus. - * Limit CPU config access to installed cpus. - * - * Parameters: - * @param[in] sMainData* pDat = our global state, number of nodes discovered. - * --------------------------------------------------------------------------------------- - */ -static void finializeCoherentInit(sMainData *pDat) -{ - u8 curNode; - - u8 totalCores = 0; - for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) - { - totalCores += pDat->nb->getNumCoresOnNode(curNode, pDat->nb); - } - - for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) - { - pDat->nb->setTotalNodesAndCores(curNode, pDat->NodesDiscovered+1, totalCores, pDat->nb); - } - - for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) - { - pDat->nb->limitNodes(curNode, pDat->nb); - } - -} - -/*---------------------------------------------------------------------------------------- - * void - * coherentInit(sMainData *pDat) - * - * Description: - * Perform discovery and initialization of the coherent fabric. - * - * Parameters: - * @param[in] sMainData* pDat = our global state - * --------------------------------------------------------------------------------------- - */ -static void coherentInit(sMainData *pDat) -{ -#ifdef HT_BUILD_NC_ONLY - /* Replace discovery process with: - * No other nodes, no coherent links - * Enable routing tables on currentNode, for power on self route - */ - pDat->NodesDiscovered = 0; - pDat->TotalLinks = 0; - pDat->nb->enableRoutingTables(0, pDat->nb); -#else - u8 i, j; - - pDat->NodesDiscovered = 0; - pDat->TotalLinks = 0; - for (i = 0; i < MAX_NODES; i++) - { - pDat->sysDegree[i] = 0; - for (j = 0; j < MAX_NODES; j++) - { - pDat->sysMatrix[i][j] = 0; - } - } - - htDiscoveryFloodFill(pDat); - lookupComputeAndLoadRoutingTables(pDat); -#endif - finializeCoherentInit(pDat); -} - -/*************************************************************************** - *** Non-coherent init code *** - *** Algorithms *** - ***************************************************************************/ -/*---------------------------------------------------------------------------------------- - * void - * processLink(u8 node, u8 link, sMainData *pDat) - * - * Description: - * Process a non-coherent link, enabling a range of bus numbers, and setting the device - * ID for all devices found - * - * Parameters: - * @param[in] u8 node = Node on which to process nc init - * @param[in] u8 link = The non-coherent link on that node - * @param[in] sMainData* pDat = our global state - * --------------------------------------------------------------------------------------- - */ -static void processLink(u8 node, u8 link, sMainData *pDat) -{ - u8 secBus, subBus; - u32 currentBUID; - u32 temp; - u32 unitIDcnt; - SBDFO currentPtr; - u8 depth; - const u8 *pSwapPtr; - - SBDFO lastSBDFO = ILLEGAL_SBDFO; - u8 lastLink = 0; - - ASSERT(node < pDat->nb->maxNodes && link < pDat->nb->maxLinks); - - if ((pDat->HtBlock->AMD_CB_OverrideBusNumbers == NULL) - || !pDat->HtBlock->AMD_CB_OverrideBusNumbers(node, link, &secBus, &subBus)) - { - /* Assign Bus numbers */ - if (pDat->AutoBusCurrent >= pDat->HtBlock->AutoBusMax) - { - /* If we run out of Bus Numbers notify, if call back unimplemented or if it - * returns, skip this chain - */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHTEventNcohBusMaxExceed evt; - evt.eSize = sizeof(sHTEventNcohBusMaxExceed); - evt.node = node; - evt.link = link; - evt.bus = pDat->AutoBusCurrent; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUS_MAX_EXCEED,(u8 *)&evt); - } - STOP_HERE; - return; - } - - if (pDat->UsedCfgMapEntires >= 4) - { - /* If we have used all the PCI Config maps we can't add another chain. - * Notify and if call back is unimplemented or returns, skip this chain. - */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventNcohCfgMapExceed evt; - evt.eSize = sizeof(sHtEventNcohCfgMapExceed); - evt.node = node; - evt.link = link; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, - HT_EVENT_NCOH_CFG_MAP_EXCEED, - (u8 *)&evt); - } - STOP_HERE; - return; - } - - secBus = pDat->AutoBusCurrent; - subBus = secBus + pDat->HtBlock->AutoBusIncrement-1; - pDat->AutoBusCurrent += pDat->HtBlock->AutoBusIncrement; - } - - pDat->nb->setCFGAddrMap(pDat->UsedCfgMapEntires, secBus, subBus, node, link, pDat, pDat->nb); - pDat->UsedCfgMapEntires++; - - if ((pDat->HtBlock->AMD_CB_ManualBUIDSwapList != NULL) - && pDat->HtBlock->AMD_CB_ManualBUIDSwapList(node, link, &pSwapPtr)) - { - /* Manual non-coherent BUID assignment */ - currentBUID = 1; - - /* Assign BUID's per manual override */ - while (*pSwapPtr != 0xFF) - { - currentPtr = MAKE_SBDFO(0, secBus, *pSwapPtr, 0, 0); - pSwapPtr++; - - do - { - AmdPCIFindNextCap(¤tPtr); - ASSERT(currentPtr != ILLEGAL_SBDFO); - AmdPCIRead(currentPtr, &temp); - } while (!IS_HT_SLAVE_CAPABILITY(temp)); - - currentBUID = *pSwapPtr; - pSwapPtr++; - AmdPCIWriteBits(currentPtr, 20, 16, ¤tBUID); - } - - /* Build chain of devices */ - depth = 0; - pSwapPtr++; - while (*pSwapPtr != 0xFF) - { - pDat->PortList[pDat->TotalLinks*2].NodeID = node; - if (depth == 0) - { - pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU; - pDat->PortList[pDat->TotalLinks*2].Link = link; - } - else - { - pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO; - pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink; - pDat->PortList[pDat->TotalLinks*2].HostLink = link; - pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1; - pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO; - } - - pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO; - pDat->PortList[pDat->TotalLinks*2+1].NodeID = node; - pDat->PortList[pDat->TotalLinks*2+1].HostLink = link; - pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth; - - currentPtr = MAKE_SBDFO(0, secBus, (*pSwapPtr & 0x3F), 0, 0); - do - { - AmdPCIFindNextCap(¤tPtr); - ASSERT(currentPtr != ILLEGAL_SBDFO); - AmdPCIRead(currentPtr, &temp); - } while (!IS_HT_SLAVE_CAPABILITY(temp)); - pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr; - lastSBDFO = currentPtr; - - /* Bit 6 indicates whether orientation override is desired. - * Bit 7 indicates the upstream link if overriding. - */ - /* assert catches at least the one known incorrect setting */ - ASSERT ((*pSwapPtr & 0x40) || (!(*pSwapPtr & 0x80))); - if (*pSwapPtr & 0x40) - { - /* Override the device's orientation */ - lastLink = *pSwapPtr >> 7; - } - else - { - /* Detect the device's orientation */ - AmdPCIReadBits(currentPtr, 26, 26, &temp); - lastLink = (u8)temp; - } - pDat->PortList[pDat->TotalLinks*2+1].Link = lastLink; - - depth++; - pDat->TotalLinks++; - pSwapPtr++; - } - } - else - { - /* Automatic non-coherent device detection */ - depth = 0; - currentBUID = 1; - while (1) - { - currentPtr = MAKE_SBDFO(0, secBus, 0, 0, 0); - - AmdPCIRead(currentPtr, &temp); - if (temp == 0xFFFFFFFF) - /* No device found at currentPtr */ - break; - - if (pDat->TotalLinks == MAX_PLATFORM_LINKS) - { - /* - * Exceeded our capacity to describe all non-coherent links found in the system. - * Error strategy: - * Auto recovery is not possible because data space is already all used. - */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventNcohLinkExceed evt; - evt.eSize = sizeof(sHtEventNcohLinkExceed); - evt.node = node; - evt.link = link; - evt.depth = depth; - evt.maxLinks = pDat->nb->maxLinks; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, - HT_EVENT_NCOH_LINK_EXCEED, - (u8 *)&evt); - } - /* Force link loop to halt */ - STOP_HERE; - break; - } - - pDat->PortList[pDat->TotalLinks*2].NodeID = node; - if (depth == 0) - { - pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU; - pDat->PortList[pDat->TotalLinks*2].Link = link; - } - else - { - pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO; - pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink; - pDat->PortList[pDat->TotalLinks*2].HostLink = link; - pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1; - pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO; - } - - pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO; - pDat->PortList[pDat->TotalLinks*2+1].NodeID = node; - pDat->PortList[pDat->TotalLinks*2+1].HostLink = link; - pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth; - - do - { - AmdPCIFindNextCap(¤tPtr); - ASSERT(currentPtr != ILLEGAL_SBDFO); - AmdPCIRead(currentPtr, &temp); - } while (!IS_HT_SLAVE_CAPABILITY(temp)); - - AmdPCIReadBits(currentPtr, 25, 21, &unitIDcnt); - if ((unitIDcnt + currentBUID > 31) || ((secBus == 0) && (unitIDcnt + currentBUID > 24))) - { - /* An error handler for the case where we run out of BUID's on a chain */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventNcohBuidExceed evt; - evt.eSize = sizeof(sHtEventNcohBuidExceed); - evt.node = node; - evt.link = link; - evt.depth = depth; - evt.currentBUID = (uint8)currentBUID; - evt.unitCount = (uint8)unitIDcnt; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUID_EXCEED,(u8 *)&evt); - } - STOP_HERE; - break; - } - AmdPCIWriteBits(currentPtr, 20, 16, ¤tBUID); - - - currentPtr += MAKE_SBDFO(0, 0, currentBUID, 0, 0); - AmdPCIReadBits(currentPtr, 20, 16, &temp); - if (temp != currentBUID) - { - /* An error handler for this critical error */ - if (pDat->HtBlock->AMD_CB_EventNotify) - { - sHtEventNcohDeviceFailed evt; - evt.eSize = sizeof(sHtEventNcohDeviceFailed); - evt.node = node; - evt.link = link; - evt.depth = depth; - evt.attemptedBUID = (uint8)currentBUID; - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_DEVICE_FAILED,(u8 *)&evt); - } - STOP_HERE; - break; - } - - AmdPCIReadBits(currentPtr, 26, 26, &temp); - pDat->PortList[pDat->TotalLinks*2+1].Link = (u8)temp; - pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr; - - lastLink = (u8)temp; - lastSBDFO = currentPtr; - - depth++; - pDat->TotalLinks++; - currentBUID += unitIDcnt; - } - if (pDat->HtBlock->AMD_CB_EventNotify) - { - /* Provide information on automatic device results */ - sHtEventNcohAutoDepth evt; - evt.eSize = sizeof(sHtEventNcohAutoDepth); - evt.node = node; - evt.link = link; - evt.depth = (depth - 1); - - pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,HT_EVENT_NCOH_AUTO_DEPTH,(u8 *)&evt); - } - } -} - - -/*---------------------------------------------------------------------------------------- - * void - * ncInit(sMainData *pDat) - * - * Description: - * Initialize the non-coherent fabric. Begin with the compat link on the BSP, then - * find and initialize all other non-coherent chains. - * - * Parameters: - * @param[in] sMainData* pDat = our global state - * --------------------------------------------------------------------------------------- - */ -static void ncInit(sMainData *pDat) -{ - u8 node, link; - u8 compatLink; - - compatLink = pDat->nb->readSbLink(pDat->nb); - processLink(0, compatLink, pDat); - - for (node = 0; node <= pDat->NodesDiscovered; node++) - { - for (link = 0; link < pDat->nb->maxLinks; link++) - { - if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(node, link)) - continue; /* Skip the link */ - - if (node == 0 && link == compatLink) - continue; - - if (pDat->nb->readTrueLinkFailStatus(node, link, pDat, pDat->nb)) - continue; - - if (pDat->nb->verifyLinkIsNonCoherent(node, link, pDat->nb)) - processLink(node, link, pDat); - } - } -} - -/*************************************************************************** - *** Link Optimization *** - ***************************************************************************/ - -/*---------------------------------------------------------------------------------------- - * void - * regangLinks(sMainData *pDat) - * - * Description: - * Test the sublinks of a link to see if they qualify to be reganged. If they do, - * update the port list data to indicate that this should be done. Note that no - * actual hardware state is changed in this routine. - * - * Parameters: - * @param[in,out] sMainData* pDat = our global state - * --------------------------------------------------------------------------------------- - */ -static void regangLinks(sMainData *pDat) -{ -#ifndef HT_BUILD_NC_ONLY - u8 i, j; - for (i = 0; i < pDat->TotalLinks*2; i += 2) - { - ASSERT(pDat->PortList[i].Type < 2 && pDat->PortList[i].Link < pDat->nb->maxLinks); /* Data validation */ - ASSERT(pDat->PortList[i+1].Type < 2 && pDat->PortList[i+1].Link < pDat->nb->maxLinks); /* data validation */ - ASSERT(!(pDat->PortList[i].Type == PORTLIST_TYPE_IO && pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU)); /* ensure src is closer to the bsp than dst */ - - /* Regang is false unless we pass all conditions below */ - pDat->PortList[i].SelRegang = FALSE; - pDat->PortList[i+1].SelRegang = FALSE; - - if ((pDat->PortList[i].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[i+1].Type != PORTLIST_TYPE_CPU)) - continue; /* Only process CPU to CPU links */ - - for (j = i+2; j < pDat->TotalLinks*2; j += 2) - { - if ((pDat->PortList[j].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[j+1].Type != PORTLIST_TYPE_CPU)) - continue; /* Only process CPU to CPU links */ - - if (pDat->PortList[i].NodeID != pDat->PortList[j].NodeID) - continue; /* Links must be from the same source */ - - if (pDat->PortList[i+1].NodeID != pDat->PortList[j+1].NodeID) - continue; /* Link must be to the same target */ - - if ((pDat->PortList[i].Link & 3) != (pDat->PortList[j].Link & 3)) - continue; /* Ensure same source base port */ - - if ((pDat->PortList[i+1].Link & 3) != (pDat->PortList[j+1].Link & 3)) - continue; /* Ensure same destination base port */ - - if ((pDat->PortList[i].Link & 4) != (pDat->PortList[i+1].Link & 4)) - continue; /* Ensure sublink0 routes to sublink0 */ - - ASSERT((pDat->PortList[j].Link & 4) == (pDat->PortList[j+1].Link & 4)); /* (therefore sublink1 routes to sublink1) */ - - if (pDat->HtBlock->AMD_CB_SkipRegang && - pDat->HtBlock->AMD_CB_SkipRegang(pDat->PortList[i].NodeID, - pDat->PortList[i].Link & 0x03, - pDat->PortList[i+1].NodeID, - pDat->PortList[i+1].Link & 0x03)) - { - continue; /* Skip regang */ - } - - - pDat->PortList[i].Link &= 0x03; /* Force to point to sublink0 */ - pDat->PortList[i+1].Link &= 0x03; - pDat->PortList[i].SelRegang = TRUE; /* Enable link reganging */ - pDat->PortList[i+1].SelRegang = TRUE; - pDat->PortList[i].PrvWidthOutCap = HT_WIDTH_16_BITS; - pDat->PortList[i+1].PrvWidthOutCap = HT_WIDTH_16_BITS; - pDat->PortList[i].PrvWidthInCap = HT_WIDTH_16_BITS; - pDat->PortList[i+1].PrvWidthInCap = HT_WIDTH_16_BITS; - - /* Delete PortList[j, j+1], slow but easy to debug implementation */ - pDat->TotalLinks--; - Amdmemcpy(&(pDat->PortList[j]), &(pDat->PortList[j+2]), sizeof(sPortDescriptor)*(pDat->TotalLinks*2-j)); - Amdmemset(&(pDat->PortList[pDat->TotalLinks*2]), INVALID_LINK, sizeof(sPortDescriptor)*2); - - /* //High performance, but would make debuging harder due to 'shuffling' of the records */ - /* //Amdmemcpy(PortList[TotalPorts-2], PortList[j], SIZEOF(sPortDescriptor)*2); */ - /* //TotalPorts -=2; */ - - break; /* Exit loop, advance to PortList[i+2] */ - } - } -#endif /* HT_BUILD_NC_ONLY */ -} - -static void detectIoLinkIsochronousCapable(sMainData *pDat) -{ - uint8_t i; - unsigned char iommu; - uint8_t isochronous_capable = 0; - - iommu = 1; - get_option(&iommu, "iommu"); - - for (i = 0; i < pDat->TotalLinks*2; i += 2) { - if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_IO)) { - if ((pDat->PortList[i].PrvFeatureCap & 0x1) && (pDat->PortList[i+1].PrvFeatureCap & 0x1)) { - pDat->PortList[i].enable_isochronous_mode = 1; - pDat->PortList[i+1].enable_isochronous_mode = 1; - isochronous_capable = 1; - } else { - pDat->PortList[i].enable_isochronous_mode = 0; - pDat->PortList[i+1].enable_isochronous_mode = 0; - } - } - } - - if (isochronous_capable && iommu) { - printk(BIOS_DEBUG, "Forcing HT links to isochronous mode due to enabled IOMMU\n"); - /* Isochronous mode must be set on all links if the IOMMU is enabled */ - for (i = 0; i < pDat->TotalLinks*2; i += 2) { - pDat->PortList[i].enable_isochronous_mode = 1; - pDat->PortList[i+1].enable_isochronous_mode = 1; - } - } -} - -/*---------------------------------------------------------------------------------------- - * void - * selectOptimalWidthAndFrequency(sMainData *pDat) - * - * Description: - * For all links: - * Examine both sides of a link and determine the optimal frequency and width, - * taking into account externally provided limits and enforcing any other limit - * or matching rules as applicable except sublink balancing. Update the port - * list date with the optimal settings. - * Note no hardware state changes in this routine. - * - * Parameters: - * @param[in,out] sMainData* pDat = our global state, port list data - * --------------------------------------------------------------------------------------- - */ -static void selectOptimalWidthAndFrequency(sMainData *pDat) -{ - u8 i, j; - uint32_t temp; - uint32_t cbPCBFreqLimit; - uint32_t cbPCBFreqLimit_NVRAM; - u8 cbPCBABDownstreamWidth; - u8 cbPCBBAUpstreamWidth; - - cbPCBFreqLimit_NVRAM = 0xfffff; - if (get_option(&temp, "hypertransport_speed_limit") == CB_SUCCESS) - cbPCBFreqLimit_NVRAM = ht_speed_limit[temp & 0xf]; - - if (!is_fam15h()) { - /* FIXME - * By default limit frequency to 2.6 GHz as there are residual - * problems with HT v3.1 implementation on at least some Socket G34 - * mainboards / Fam10h CPUs. - * Debug the issues and reenable this... - */ - if (cbPCBFreqLimit_NVRAM > 0xffff) - cbPCBFreqLimit_NVRAM = 0xffff; - } - - for (i = 0; i < pDat->TotalLinks*2; i += 2) - { - cbPCBFreqLimit = 0xfffff; // Maximum allowed by autoconfiguration - if (pDat->HtBlock->ht_link_configuration) - cbPCBFreqLimit = ht_speed_mhz_to_hw(pDat->HtBlock->ht_link_configuration->ht_speed_limit); - cbPCBFreqLimit = min(cbPCBFreqLimit, cbPCBFreqLimit_NVRAM); - -#if CONFIG(LIMIT_HT_DOWN_WIDTH_8) - cbPCBABDownstreamWidth = 8; -#else - cbPCBABDownstreamWidth = 16; -#endif - -#if CONFIG(LIMIT_HT_UP_WIDTH_8) - cbPCBBAUpstreamWidth = 8; -#else - cbPCBBAUpstreamWidth = 16; -#endif - - if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU)) - { - if (pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits) - { - pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits( - pDat->PortList[i].NodeID, - pDat->PortList[i].Link, - pDat->PortList[i+1].NodeID, - pDat->PortList[i+1].Link, - &cbPCBABDownstreamWidth, - &cbPCBBAUpstreamWidth, &cbPCBFreqLimit - ); - } - } - else - { - if (pDat->HtBlock->AMD_CB_IOPCBLimits) - { - pDat->HtBlock->AMD_CB_IOPCBLimits( - pDat->PortList[i+1].NodeID, - pDat->PortList[i+1].HostLink, - pDat->PortList[i+1].HostDepth, - &cbPCBABDownstreamWidth, - &cbPCBBAUpstreamWidth, &cbPCBFreqLimit - ); - } - } - - temp = pDat->PortList[i].PrvFrequencyCap; - temp &= pDat->PortList[i+1].PrvFrequencyCap; - temp &= cbPCBFreqLimit; - pDat->PortList[i].CompositeFrequencyCap = temp; - pDat->PortList[i+1].CompositeFrequencyCap = temp; - - ASSERT (temp != 0); - for (j = 19;; j--) - { - if ((j == 16) || (j == 15)) - continue; - if (temp & ((uint32_t)1 << j)) - break; - } - - pDat->PortList[i].SelFrequency = j; - pDat->PortList[i+1].SelFrequency = j; - - temp = pDat->PortList[i].PrvWidthOutCap; - if (pDat->PortList[i+1].PrvWidthInCap < temp) - temp = pDat->PortList[i+1].PrvWidthInCap; - if (cbPCBABDownstreamWidth < temp) - temp = cbPCBABDownstreamWidth; - pDat->PortList[i].SelWidthOut = (u8)temp; - pDat->PortList[i+1].SelWidthIn = (u8)temp; - - temp = pDat->PortList[i].PrvWidthInCap; - if (pDat->PortList[i+1].PrvWidthOutCap < temp) - temp = pDat->PortList[i+1].PrvWidthOutCap; - if (cbPCBBAUpstreamWidth < temp) - temp = cbPCBBAUpstreamWidth; - pDat->PortList[i].SelWidthIn = (u8)temp; - pDat->PortList[i+1].SelWidthOut = (u8)temp; - } -} - -/*---------------------------------------------------------------------------------------- - * void - * hammerSublinkFixup(sMainData *pDat) - * - * Description: - * Iterate through all links, checking the frequency of each sublink pair. Make the - * adjustment to the port list data so that the frequencies are at a valid ratio, - * reducing frequency as needed to achieve this. (All links support the minimum 200 MHz - * frequency.) Repeat the above until no adjustments are needed. - * Note no hardware state changes in this routine. - * - * Parameters: - * @param[in,out] sMainData* pDat = our global state, link state and port list - * --------------------------------------------------------------------------------------- - */ -static void hammerSublinkFixup(sMainData *pDat) -{ -#ifndef HT_BUILD_NC_ONLY - u8 i, j, k; - BOOL changes, downgrade; - - u8 hiIndex; - u8 hiFreq, loFreq; - - u32 temp; - - do - { - changes = FALSE; - for (i = 0; i < pDat->TotalLinks*2; i++) - { - if (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) /* Must be a CPU link */ - continue; - if (pDat->PortList[i].Link < 4) /* Only look for sublink1's */ - continue; - - for (j = 0; j < pDat->TotalLinks*2; j++) - { - /* Step 1. Find the matching sublink0 */ - if (pDat->PortList[j].Type != PORTLIST_TYPE_CPU) - continue; - if (pDat->PortList[j].NodeID != pDat->PortList[i].NodeID) - continue; - if (pDat->PortList[j].Link != (pDat->PortList[i].Link & 0x03)) - continue; - - /* Step 2. Check for an illegal frequency ratio */ - if (pDat->PortList[i].SelFrequency >= pDat->PortList[j].SelFrequency) - { - hiIndex = i; - hiFreq = pDat->PortList[i].SelFrequency; - loFreq = pDat->PortList[j].SelFrequency; - } - else - { - hiIndex = j; - hiFreq = pDat->PortList[j].SelFrequency; - loFreq = pDat->PortList[i].SelFrequency; - } - - if (hiFreq == loFreq) - break; /* The frequencies are 1:1, no need to do anything */ - - downgrade = FALSE; - - if (hiFreq == 13) - { - if ((loFreq != 7) && /* {13, 7} 2400MHz / 1200MHz 2:1 */ - (loFreq != 4) && /* {13, 4} 2400MHz / 600MHz 4:1 */ - (loFreq != 2)) /* {13, 2} 2400MHz / 400MHz 6:1 */ - downgrade = TRUE; - } - else if (hiFreq == 11) - { - if ((loFreq != 6)) /* {11, 6} 2000MHz / 1000MHz 2:1 */ - downgrade = TRUE; - } - else if (hiFreq == 9) - { - if ((loFreq != 5) && /* { 9, 5} 1600MHz / 800MHz 2:1 */ - (loFreq != 2) && /* { 9, 2} 1600MHz / 400MHz 4:1 */ - (loFreq != 0)) /* { 9, 0} 1600MHz / 200MHz 8:1 */ - downgrade = TRUE; - } - else if (hiFreq == 7) - { - if ((loFreq != 4) && /* { 7, 4} 1200MHz / 600MHz 2:1 */ - (loFreq != 0)) /* { 7, 0} 1200MHz / 200MHz 6:1 */ - downgrade = TRUE; - } - else if (hiFreq == 5) - { - if ((loFreq != 2) && /* { 5, 2} 800MHz / 400MHz 2:1 */ - (loFreq != 0)) /* { 5, 0} 800MHz / 200MHz 4:1 */ - downgrade = TRUE; - } - else if (hiFreq == 2) - { - if ((loFreq != 0)) /* { 2, 0} 400MHz / 200MHz 2:1 */ - downgrade = TRUE; - } - else - { - downgrade = TRUE; /* no legal ratios for hiFreq */ - } - - /* Step 3. Downgrade the higher of the two frequencies, and set nochanges to FALSE */ - if (downgrade) - { - /* Although the problem was with the port specified by hiIndex, we need to */ - /* downgrade both ends of the link. */ - hiIndex = hiIndex & 0xFE; /* Select the 'upstream' (i.e. even) port */ - - temp = pDat->PortList[hiIndex].CompositeFrequencyCap; - - /* Remove hiFreq from the list of valid frequencies */ - temp = temp & ~((uint32)1 << hiFreq); - ASSERT (temp != 0); - pDat->PortList[hiIndex].CompositeFrequencyCap = temp; - pDat->PortList[hiIndex+1].CompositeFrequencyCap = temp; - - for (k = 19;; k--) - { - if ((j == 16) || (j == 15)) - continue; - if (temp & ((uint32_t)1 << k)) - break; - } - - pDat->PortList[hiIndex].SelFrequency = k; - pDat->PortList[hiIndex+1].SelFrequency = k; - - changes = TRUE; - } - } - } - } while (changes); /* Repeat until a valid configuration is reached */ -#endif /* HT_BUILD_NC_ONLY */ -} - -/*---------------------------------------------------------------------------------------- - * void - * linkOptimization(sMainData *pDat) - * - * Description: - * Based on link capabilities, apply optimization rules to come up with the real best - * settings, including several external limit decision from call backs. This includes - * handling of sublinks. Finally, after the port list data is updated, set the hardware - * state for all links. - * - * Parameters: - * @param[in] sMainData* pDat = our global state - * --------------------------------------------------------------------------------------- - */ -static void linkOptimization(sMainData *pDat) -{ - pDat->nb->gatherLinkData(pDat, pDat->nb); - regangLinks(pDat); - if (is_fam15h()) - detectIoLinkIsochronousCapable(pDat); - selectOptimalWidthAndFrequency(pDat); - hammerSublinkFixup(pDat); - pDat->nb->setLinkData(pDat, pDat->nb); -} - - -/*---------------------------------------------------------------------------------------- - * void - * trafficDistribution(sMainData *pDat) - * - * Description: - * In the case of a two node system with both sublinks used, enable the traffic - * distribution feature. - * - * Parameters: - * @param[in] sMainData* pDat = our global state, port list data - * --------------------------------------------------------------------------------------- - */ -static void trafficDistribution(sMainData *pDat) -{ -#ifndef HT_BUILD_NC_ONLY - u32 links01, links10; - u8 linkCount; - u8 i; - - /* Traffic Distribution is only used when there are exactly two nodes in the system */ - if (pDat->NodesDiscovered+1 != 2) - return; - - links01 = 0; - links10 = 0; - linkCount = 0; - for (i = 0; i < pDat->TotalLinks*2; i += 2) - { - if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU)) - { - links01 |= (u32)1 << pDat->PortList[i].Link; - links10 |= (u32)1 << pDat->PortList[i+1].Link; - linkCount++; - } - } - ASSERT(linkCount != 0); - if (linkCount == 1) - return; /* Don't setup Traffic Distribution if only one link is being used */ - - pDat->nb->writeTrafficDistribution(links01, links10, pDat->nb); -#endif /* HT_BUILD_NC_ONLY */ -} - -/*---------------------------------------------------------------------------------------- - * void - * tuning(sMainData *pDat) - * - * Description: - * Handle system and performance tunings, such as traffic distribution, fifo and - * buffer tuning, and special config tunings. - * - * Parameters: - * @param[in] sMainData* pDat = our global state, port list data - * --------------------------------------------------------------------------------------- - */ -static void tuning(sMainData *pDat) -{ - u8 i; - - /* See if traffic distribution can be done and do it if so - * or allow system specific customization - */ - if ((pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution == NULL) - || !pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution()) - { - trafficDistribution(pDat); - } - - /* For each node, invoke northbridge specific buffer tunings or - * system specific customizations. - */ - for (i = 0; i < pDat->NodesDiscovered + 1; i++) - { - if ((pDat->HtBlock->AMD_CB_CustomizeBuffers == NULL) - || !pDat->HtBlock->AMD_CB_CustomizeBuffers(i)) - { - pDat->nb->bufferOptimizations(i, pDat, pDat->nb); - } - } -} - -/*---------------------------------------------------------------------------------------- - * BOOL - * isSanityCheckOk() - * - * Description: - * Perform any general sanity checks which should prevent HT from running if they fail. - * Currently only the "Must run on BSP only" check. - * - * Parameters: - * @param[out] result BOOL = true if check is ok, false if it failed - * --------------------------------------------------------------------------------------- - */ -static BOOL isSanityCheckOk(void) -{ - uint64 qValue; - - AmdMSRRead(LAPIC_BASE_MSR, &qValue); - - return ((qValue.lo & LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR) != 0); -} - -/*************************************************************************** - *** HT Initialize *** - ***************************************************************************/ - -/*---------------------------------------------------------------------------------------- - * void - * htInitialize(AMD_HTBLOCK *pBlock) - * - * Description: - * This is the top level external interface for Hypertransport Initialization. - * Create our initial internal state, initialize the coherent fabric, - * initialize the non-coherent chains, and perform any required fabric tuning or - * optimization. - * - * Parameters: - * @param[in] AMD_HTBLOCK* pBlock = Our Initial State including possible - * topologies and routings, non coherent bus - * assignment info, and actual - * wrapper or OEM call back routines. - * --------------------------------------------------------------------------------------- - */ -void amdHtInitialize(AMD_HTBLOCK *pBlock) -{ - sMainData pDat; - cNorthBridge nb; - - if (isSanityCheckOk()) - { - newNorthBridge(0, &nb); - - pDat.HtBlock = pBlock; - pDat.nb = &nb; - pDat.sysMpCap = nb.maxNodes; - nb.isCapable(0, &pDat, pDat.nb); - coherentInit(&pDat); - - pDat.AutoBusCurrent = pBlock->AutoBusStart; - pDat.UsedCfgMapEntires = 0; - ncInit(&pDat); - linkOptimization(&pDat); - tuning(&pDat); - } -} |