/* * This file is part of the coreboot project. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /*---------------------------------------------------------------------------- * MODULES USED * *---------------------------------------------------------------------------- */ #undef FILECODE #define FILECODE 0xF002 #include "h3finit.h" #include "h3ffeat.h" #include "h3ncmn.h" #include "AsPsNb.h" /*---------------------------------------------------------------------------- * DEFINITIONS AND MACROS * *---------------------------------------------------------------------------- */ /* CPU Northbridge Functions */ #define CPU_HTNB_FUNC_00 0 #define CPU_HTNB_FUNC_04 4 #define CPU_ADDR_FUNC_01 1 #define CPU_NB_FUNC_03 3 /* Function 0 registers */ #define REG_ROUTE0_0X40 0x40 #define REG_ROUTE1_0X44 0x44 #define REG_NODE_ID_0X60 0x60 #define REG_UNIT_ID_0X64 0x64 #define REG_LINK_TRANS_CONTROL_0X68 0x68 #define REG_LINK_INIT_CONTROL_0X6C 0x6C #define REG_HT_CAP_BASE_0X80 0x80 #define REG_HT_LINK_RETRY0_0X130 0x130 #define REG_HT_TRAFFIC_DIST_0X164 0x164 #define REG_HT_LINK_EXT_CONTROL0_0X170 0x170 #define HT_CONTROL_CLEAR_CRC (~(3 << 8)) /* Function 1 registers */ #define REG_ADDR_CONFIG_MAP0_1XE0 0xE0 #define CPU_ADDR_NUM_CONFIG_MAPS 4 /* Function 3 registers */ #define REG_NB_SRI_XBAR_BUF_3X70 0x70 #define REG_NB_MCT_XBAR_BUF_3X78 0x78 #define REG_NB_FIFOPTR_3XDC 0xDC #define REG_NB_CAPABILITY_3XE8 0xE8 #define REG_NB_CPUID_3XFC 0xFC #define REG_NB_LINK_XCS_TOKEN0_3X148 0x148 #define REG_NB_DOWNCORE_3X190 0x190 /* Function 4 registers */ /*---------------------------------------------------------------------------- * TYPEDEFS AND STRUCTURES * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * PROTOTYPES OF LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ /*************************************************************************** *** FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS *** ***************************************************************************/ /**---------------------------------------------------------------------------------------- * * SBDFO * makeLinkBase(u8 currentNode, u8 currentLink) * * Description: * Private to northbridge implementation. Return the HT Host capability base * PCI config address for a link. * * Parameters: * @param[in] u8 node = the node this link is on * @param[in] u8 link = the link * @param[out] SBDFO result = the pci config address * * --------------------------------------------------------------------------------------- */ static SBDFO makeLinkBase(u8 node, u8 link) { SBDFO linkBase; /* With rev F can not be called with a 4th link or with the sublinks */ if (link < 4) linkBase = MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_HT_CAP_BASE_0X80 + link*HT_HOST_CAP_SIZE); else linkBase = MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_04, REG_HT_CAP_BASE_0X80 + (link-4)*HT_HOST_CAP_SIZE); return linkBase; } /**---------------------------------------------------------------------------------------- * * void * setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue) * * Description: * Private to northbridge implementation. Provide a common routine for accessing the * HT Link Control registers (84, a4, c4, e4), to enforce not clearing the * HT CRC error bits. Replaces direct use of AmdPCIWriteBits(). * NOTE: This routine is called for IO Devices as well as CPUs! * * Parameters: * @param[in] SBDFO reg = the PCI config address the control register * @param[in] u8 hiBit = the high bit number * @param[in] u8 loBit = the low bit number * @param[in] u8 pValue = the value to write to that bit range. Bit 0 => loBit. * * --------------------------------------------------------------------------------------- */ static void setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue) { u32 temp, mask; ASSERT((hiBit < 32) && (loBit < 32) && (hiBit >= loBit) && ((reg & 0x3) == 0)); ASSERT((hiBit < 8) || (loBit > 9)); /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */ if ((hiBit-loBit) != 31) mask = (((u32)1 << (hiBit-loBit+1))-1); else mask = (u32)0xFFFFFFFF; AmdPCIRead(reg, &temp); temp &= ~(mask << loBit); temp |= (*pValue & mask) << loBit; temp &= (u32)HT_CONTROL_CLEAR_CRC; AmdPCIWrite(reg, &temp); } /**---------------------------------------------------------------------------------------- * * void * writeRoutingTable(u8 node, u8 target, u8 Link, cNorthBridge *nb) * * Description: * This routine will modify the routing tables on the * SourceNode to cause it to route both request and response traffic to the * targetNode through the specified Link. * * NOTE: This routine is to be used for early discovery and initialization. The * final routing tables must be loaded some other way because this * routine does not address the issue of probes, or independent request * response paths. * * Parameters: * @param[in] u8 node = the node that will have it's routing tables modified. * @param[in] u8 target = For routing to node target * @param[in] u8 Link = Link from node to target * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void writeRoutingTable(u8 node, u8 target, u8 link, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 temp = (nb->selfRouteResponseMask | nb->selfRouteRequestMask) << (link + 1); ASSERT((node < nb->maxNodes) && (target < nb->maxNodes) && (link < nb->maxLinks)); AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_ROUTE0_0X40 + target*4), &temp); #else STOP_HERE; #endif } /**---------------------------------------------------------------------------------------- * * void * writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb) * * Description: * Modifies the NodeID register on the target node * * Parameters: * @param[in] u8 node = the node that will have its NodeID altered. * @param[in] u8 nodeID = the new value for NodeID * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb) { u32 temp = nodeID; ASSERT((node < nb->maxNodes) && (nodeID < nb->maxNodes)); AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_NODE_ID_0X60), 2, 0, &temp); } /**---------------------------------------------------------------------------------------- * * void * readDefLnk(u8 node, cNorthBridge *nb) * * Description: * Read the DefLnk (the source link of the current packet) * from node * * Parameters: * @param[in] u8 node = the node that will have its NodeID altered. * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 result = The HyperTransport link where the request to * read the default link came from. Since this * code is running on the BSP, this should be the link * pointing back towards the BSP. * * --------------------------------------------------------------------------------------- */ u8 readDefLnk(u8 node, cNorthBridge *nb) { u32 deflink = 0; SBDFO licr; u32 temp; licr = MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_LINK_INIT_CONTROL_0X6C); ASSERT((node < nb->maxNodes)); AmdPCIReadBits(licr, 3, 2, &deflink); AmdPCIReadBits(licr, 8, 8, &temp); /* on rev F, this bit is reserved == 0 */ deflink |= temp << 2; return (u8)deflink; } /**---------------------------------------------------------------------------------------- * * void * enableRoutingTables(u8 node, cNorthBridge *nb) * * Description: * Turns routing tables on for a given node * * Parameters: * @param[in] u8 node = the node that will have it's routing tables enabled * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void enableRoutingTables(u8 node, cNorthBridge *nb) { u32 temp = 0; ASSERT((node < nb->maxNodes)); AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_LINK_INIT_CONTROL_0X6C), 0, 0, &temp); } /**---------------------------------------------------------------------------------------- * * void * verifyLinkIsCoherent(u8 node, u8 Link, cNorthBridge *nbk) * * Description: * Verify that the link is coherent, connected, and ready * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] u8 link = the link on that Node to examine * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 result = true - The link has the following status * linkCon=1, Link is connected * InitComplete=1, Link initialization is complete * NC=0, Link is coherent * UniP-cLDT=0, Link is not Uniprocessor cLDT * LinkConPend=0 Link connection is not pending * false- The link has some other status * * --------------------------------------------------------------------------------------- */ BOOL verifyLinkIsCoherent(u8 node, u8 link, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 linkType; SBDFO linkBase; ASSERT((node < nb->maxNodes) && (link < nb->maxLinks)); linkBase = makeLinkBase(node, link); /* FN0_98/A4/C4 = LDT Type Register */ AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType); /* Verify LinkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0 */ return (linkType & HTHOST_TYPE_MASK) == HTHOST_TYPE_COHERENT; #else return 0; #endif /* HT_BUILD_NC_ONLY */ } /**---------------------------------------------------------------------------------------- * * bool * readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb) * * Description: * Return the LinkFailed status AFTER an attempt is made to clear the bit. * Also, call event notify if a Hardware Fault caused a synch flood on a previous boot. * * The table below summarizes correct responses of this routine. * Family before after unconnected Notify? return * 0F 0 0 0 No 0 * 0F 1 0 0 Yes 0 * 0F 1 1 X No 1 * 10 0 0 0 No 0 * 10 1 0 0 Yes 0 * 10 1 0 3 No 1 * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] u8 link = the link on that node to examine * @param[in] u8 sMainData = access to call back routine * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 result = true - the link is not connected or has hard error * false- if the link is connected * * --------------------------------------------------------------------------------------- */ BOOL readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb) { u32 before, after, unconnected, crc; SBDFO linkBase; ASSERT((node < nb->maxNodes) && (link < nb->maxLinks)); linkBase = makeLinkBase(node, link); /* Save the CRC status before doing anything else. * Read, Clear, the Re-read the error bits in the Link Control Register * FN0_84/A4/C4[4] = LinkFail bit * and the connection status, TransOff and EndOfChain */ AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 9, 8, &crc); AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before); setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before); AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &after); AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &unconnected); if (before != after) { if (!unconnected) { if (crc != 0) { /* A synch flood occurred due to HT CRC */ if (pDat->HtBlock->AMD_CB_EventNotify) { /* Pass the node and link on which the generic synch flood event occurred. */ sHtEventHWHtCrc evt; evt.eSize = sizeof(sHtEventHWHtCrc); evt.node = node; evt.link = link; evt.laneMask = (uint8)crc; pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT, HT_EVENT_HW_HTCRC, (u8 *)&evt); } } else { /* Some synch flood occurred */ if (pDat->HtBlock->AMD_CB_EventNotify) { /* Pass the node and link on which the generic synch flood event occurred. */ sHtEventHWSynchFlood evt; evt.eSize = sizeof(sHtEventHWSynchFlood); evt.node = node; evt.link = link; pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT, HT_EVENT_HW_SYNCHFLOOD, (u8 *)&evt); } } } } return ((after != 0) || unconnected); } /**---------------------------------------------------------------------------------------- * * u8 * readToken(u8 node, cNorthBridge *nb) * * Description: * Read the token stored in the scratchpad register * 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. * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 result = the Token read from the node * * --------------------------------------------------------------------------------------- */ u8 readToken(u8 node, cNorthBridge *nb) { u32 temp; ASSERT((node < nb->maxNodes)); /* Use CpuCnt as a scratch register */ /* Limiting use to 4 bits makes code GH to rev F compatible. */ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_NODE_ID_0X60), 19, 16, &temp); return (u8)temp; } /**---------------------------------------------------------------------------------------- * * void * writeToken(u8 node, u8 Value, cNorthBridge *nb) * * Description: * Write the token stored in the scratchpad register * 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. * Limiting use to 4 bits makes code GH to rev F compatible. * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void writeToken(u8 node, u8 value, cNorthBridge *nb) { u32 temp = value; ASSERT((node < nb->maxNodes)); /* Use CpuCnt as a scratch register */ /* Limiting use to 4 bits makes code GH to rev F compatible. */ AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_NODE_ID_0X60), 19, 16, &temp); } /**---------------------------------------------------------------------------------------- * * u8 * fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb) * * Description: * Return the number of cores (1 based count) on node. * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 result = the number of cores * * --------------------------------------------------------------------------------------- */ u8 fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb) { u32 temp; ASSERT((node < nb->maxNodes)); /* Read CmpCap */ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CAPABILITY_3XE8), 13, 12, &temp); /* and add one */ return (u8)(temp+1); } /**---------------------------------------------------------------------------------------- * * u8 * fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb) * * Description: * Return the number of cores (1 based count) on node. * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 result = the number of cores * * --------------------------------------------------------------------------------------- */ u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb) { u32 temp, leveling, cores; u8 i; ASSERT((node < nb->maxNodes)); /* Read CmpCap */ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CAPABILITY_3XE8), 13, 12, &temp); /* Support Downcoring */ cores = temp + 1; AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_DOWNCORE_3X190), 3, 0, &leveling); for (i=0; imaxNodes) && (totalNodes <= nb->maxNodes)); nodeIDReg = MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_NODE_ID_0X60); temp = totalCores-1; /* Rely on max number of nodes:cores for rev F and GH to make * this code work, even though we write reserved bit 20 on rev F it will be * zero in that case. */ AmdPCIWriteBits(nodeIDReg, 20, 16, &temp); temp = totalNodes-1; AmdPCIWriteBits(nodeIDReg, 6, 4, &temp); } /**---------------------------------------------------------------------------------------- * * void * limitNodes(u8 node, cNorthBridge *nb) * * Description: * Limit coherent config accesses to cpus as indicated by nodecnt. * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void limitNodes(u8 node, cNorthBridge *nb) { u32 temp = 1; ASSERT((node < nb->maxNodes)); AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_LINK_TRANS_CONTROL_0X68), 15, 15, &temp); } /**---------------------------------------------------------------------------------------- * * void * writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 BClinks, cNorthBridge *nb) * * Description: * Write the routing table entry for node to target, using the request link, response * link, and broadcast links provided. * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] u8 target = the target node for these routes * @param[in] u8 reqLink = the link for requests to target * @param[in] u8 rspLink = the link for responses to target * @param[in] u32 bClinks = the broadcast links * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 bClinks, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 value = 0; ASSERT((node < nb->maxNodes) && (target < nb->maxNodes)); if (reqLink == ROUTETOSELF) value |= nb->selfRouteRequestMask; else value |= nb->selfRouteRequestMask << (reqLink+1); if (rspLink == ROUTETOSELF) value |= nb->selfRouteResponseMask; else value |= nb->selfRouteResponseMask << (rspLink+1); /* Allow us to accept a Broadcast ourselves, then set broadcasts for routes */ value |= (u32)1 << nb->broadcastSelfBit; value |= (u32)bClinks << (nb->broadcastSelfBit + 1); AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_HTNB_FUNC_00, REG_ROUTE0_0X40 + target*4), &value); #else STOP_HERE; #endif /* HT_BUILD_NC_ONLY */ } /**---------------------------------------------------------------------------------------- * * static u32 * makeKey(u8 currentNode) * * Description: * Private routine to northbridge code. * 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. * * Parameters: * @param[in] u8 node = the node * @param[out] u32 result = the key value * * --------------------------------------------------------------------------------------- */ static u32 makeKey(u8 node) { u32 extFam, baseFam; AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC), 27, 20, &extFam); AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC), 11, 8, &baseFam); return ((u32)(baseFam << 8) | extFam); } /**---------------------------------------------------------------------------------------- * * BOOL * isCompatible(u8 currentNode, cNorthBridge *nb) * * Description: * 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. * * Parameters: * @param[in] u8 node = the node * @param[in] cNorthBridge *nb = this northbridge * @param[out] BOOL result = true: the new is compatible, false: it is not * * --------------------------------------------------------------------------------------- */ BOOL isCompatible(u8 node, cNorthBridge *nb) { return (makeKey(node) == nb->compatibleKey); } /**---------------------------------------------------------------------------------------- * * BOOL * fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb) * * Description: * Get node capability and update the minimum supported system capability. * Return whether the current configuration exceeds the capability. * * Parameters: * @param[in] u8 node = the node * @param[in,out] sMainData *pDat = sysMpCap (updated) and NodesDiscovered * @param[in] cNorthBridge *nb = this northbridge * @param[out] BOOL result = true: system is capable of current config. * false: system is not capable of current config. * * --------------------------------------------------------------------------------------- */ BOOL fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 temp; u8 maxNodes; ASSERT(node < nb->maxNodes); AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CAPABILITY_3XE8), 2, 1, &temp); if (temp > 1) { maxNodes = 8; } else { if (temp == 1) { maxNodes = 2; } else { maxNodes = 1; } } if (pDat->sysMpCap > maxNodes) { pDat->sysMpCap = maxNodes; } /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */ return (pDat->sysMpCap > pDat->NodesDiscovered); #else return 1; #endif } /**---------------------------------------------------------------------------------------- * * BOOL * fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb) * * Description: * Get node capability and update the minimum supported system capability. * Return whether the current configuration exceeds the capability. * * Parameters: * @param[in] u8 node = the node * @param[in,out] sMainData *pDat = sysMpCap (updated) and NodesDiscovered * @param[in] cNorthBridge *nb = this northbridge * @param[out] BOOL result = true: system is capable of current config. * false: system is not capable of current config. * * --------------------------------------------------------------------------------------- */ BOOL fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 temp; u8 maxNodes; ASSERT(node < nb->maxNodes); AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CAPABILITY_3XE8), 18, 16, &temp); if (temp != 0) { maxNodes = (1 << (~temp & 0x3)); /* That is, 1, 2, 4, or 8 */ } else { maxNodes = 8; } if (pDat->sysMpCap > maxNodes) { pDat->sysMpCap = maxNodes; } /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */ return (pDat->sysMpCap > pDat->NodesDiscovered); #else return 1; #endif } /**---------------------------------------------------------------------------------------- * * void * fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb) * * Description: * Disable a cHT link on node by setting F0x[E4, C4, A4, 84][TransOff, EndOfChain]=1 * * Parameters: * @param[in] u8 node = the node this link is on * @param[in] u8 link = the link to stop * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void fam0fStopLink(u8 node, u8 link, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 temp; SBDFO linkBase; ASSERT((node < nb->maxNodes) && (link < nb->maxLinks)); linkBase = makeLinkBase(node, link); /* Set TransOff, EndOfChain */ temp = 3; setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &temp); #endif } /**---------------------------------------------------------------------------------------- * * void * commonVoid() * * Description: * Nothing. * * Parameters: * None. * * --------------------------------------------------------------------------------------- */ void commonVoid() { } /**---------------------------------------------------------------------------------------- * * BOOL * commonReturnFalse() * * Description: * Return False. * * Parameters: * @param[out] BOOL result = false * --------------------------------------------------------------------------------------- */ BOOL commonReturnFalse() { return 0; } /*************************************************************************** *** Non-coherent init code *** *** Northbridge access routines *** ***************************************************************************/ /**---------------------------------------------------------------------------------------- * * u8 * readSbLink(cNorthBridge *nb) * * Description: * Return the link to the Southbridge * * Parameters: * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 results = the link to the southbridge * * --------------------------------------------------------------------------------------- */ u8 readSbLink(cNorthBridge *nb) { u32 temp; AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(0), makePCIBusFromNode(0), makePCIDeviceFromNode(0), CPU_HTNB_FUNC_00, REG_UNIT_ID_0X64), 10, 8, &temp); return (u8)temp; } /**---------------------------------------------------------------------------------------- * * BOOL * verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb) * * Description: * Verify that the link is non-coherent, connected, and ready * * Parameters: * @param[in] u8 node = the node that will be examined * @param[in] u8 link = the Link on that node to examine * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 results = true - The link has the following status * LinkCon=1, Link is connected * InitComplete=1,Link initilization is complete * NC=1, Link is coherent * UniP-cLDT=0, Link is not Uniprocessor cLDT * LinkConPend=0 Link connection is not pending * false- The link has some other status * * --------------------------------------------------------------------------------------- */ BOOL verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb) { u32 linkType; SBDFO linkBase; ASSERT((node < nb->maxNodes) && (link < nb->maxLinks)); linkBase = makeLinkBase(node, link); /* FN0_98/A4/C4 = LDT Type Register */ AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType); /* Verify linkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0 */ return (linkType & HTHOST_TYPE_MASK) == HTHOST_TYPE_NONCOHERENT; } /**---------------------------------------------------------------------------------------- * * void * ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb) * * Description: * Configure and enable config access to a non-coherent chain for the given bus range. * * Parameters: * @param[in] u8 cfgRouteIndex = the map entry to set * @param[in] u8 secBus = The secondary bus number to use * @param[in] u8 subBus = The subordinate bus number to use * @param[in] u8 targetNode = The node that shall be the recipient of the traffic * @param[in] u8 targetLink = The link that shall be the recipient of the traffic * @param[in] sMainData* pDat = our global state * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb) { u8 curNode; SBDFO linkBase; u32 temp; linkBase = makeLinkBase(targetNode, targetLink); ASSERT(secBus <= subBus); temp = secBus; AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp); /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10 * set to indicate a sublink. For node, we are currently not supporting Extended * routing tables. */ temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8) + ((u32)targetNode << 4) + (u32)3; for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode), makePCIBusFromNode(curNode), makePCIDeviceFromNode(curNode), CPU_ADDR_FUNC_01, REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex), &temp); } /**---------------------------------------------------------------------------------------- * * void * ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb) * * Description: * Configure and enable config access to a non-coherent chain for the given bus range. * * Parameters: * @param[in] u8 cfgMapIndex = the map entry to set * @param[in] u8 secBus = The secondary bus number to use * @param[in] u8 subBus = The subordinate bus number to use * @param[in] u8 targetNode = The node that shall be the recipient of the traffic * @param[in] u8 targetLink = The link that shall be the recipient of the traffic * @param[in] sMainData* pDat = our global state * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb) { u8 curNode; SBDFO linkBase; u32 temp; linkBase = makeLinkBase(targetNode, targetLink); ASSERT(secBus <= subBus); temp = secBus; AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp); temp = subBus; AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 23, 16, &temp); /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10 * set to indicate a sublink. For node, we are currently not supporting Extended * routing tables. */ temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8) + ((u32)targetNode << 4) + (u32)3; for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode), makePCIBusFromNode(curNode), makePCIDeviceFromNode(curNode), CPU_ADDR_FUNC_01, REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex), &temp); } /*************************************************************************** *** Link Optimization *** ***************************************************************************/ /**---------------------------------------------------------------------------------------- * * u8 * convertBitsToWidth(u8 value, cNorthBridge *nb) * * Description: * Given the bits set in the register field, return the width it represents * * Parameters: * @param[in] u8 value = The bits for the register * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 results = The width * * --------------------------------------------------------------------------------------- */ u8 convertBitsToWidth(u8 value, cNorthBridge *nb) { if (value == 1) { return 16; } else if (value == 0) { return 8; } else if (value == 5) { return 4; } else if (value == 4) { return 2; } STOP_HERE; /* This is an error internal condition */ } /**---------------------------------------------------------------------------------------- * * u8 * convertWidthToBits(u8 value, cNorthBridge *nb) * * Description: * Translate a desired width setting to the bits to set in the register field * * Parameters: * @param[in] u8 value = The width * @param[in] cNorthBridge *nb = this northbridge * @param[out] u8 results = The bits for the register * * --------------------------------------------------------------------------------------- */ u8 convertWidthToBits(u8 value, cNorthBridge *nb) { if (value == 16) { return 1; } else if (value == 8) { return 0; } else if (value == 4) { return 5; } else if (value == 2) { return 4; } STOP_HERE; /* This is an internal error condition */ } /**---------------------------------------------------------------------------------------- * * u16 * ht1NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb) * * Description: * Return a mask that eliminates HT frequencies that cannot be used due to a slow * northbridge frequency. * * Parameters: * @param[in] u8 node = Result could (later) be for a specific node * @param[in] cNorthBridge *nb = this northbridge * @param[out] u16 results = Frequency mask * * --------------------------------------------------------------------------------------- */ u16 ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb) { /* only up to HT1 speeds */ return (HT_FREQUENCY_LIMIT_HT1_ONLY); } /**---------------------------------------------------------------------------------------- * * u16 * fam10NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb) * * Description: * Return a mask that eliminates HT frequencies that cannot be used due to a slow * northbridge frequency. * * Parameters: * @param[in] u8 node = Result could (later) be for a specific node * @param[in] cNorthBridge *nb = this northbridge * @param[out] u16 results = Frequency mask * * --------------------------------------------------------------------------------------- */ u16 fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb) { u8 nbCOF; u16 supported; nbCOF = getMinNbCOF(); /* * nbCOF is minimum northbridge speed in hundreds of MHz. * HT can not go faster than the minimum speed of the northbridge. */ if ((nbCOF >= 6) && (nbCOF <= 26)) { /* Convert frequency to bit and all less significant bits, * by setting next power of 2 and subtracting 1. */ supported = ((u16)1 << ((nbCOF >> 1) + 2)) - 1; } else if (nbCOF > 26) { supported = HT_FREQUENCY_LIMIT_2600M; } /* unlikely cases, but include as a defensive measure, also avoid trick above */ else if (nbCOF == 4) { supported = HT_FREQUENCY_LIMIT_400M; } else if (nbCOF == 2) { supported = HT_FREQUENCY_LIMIT_200M; } else { STOP_HERE; supported = HT_FREQUENCY_LIMIT_200M; } return (fixEarlySampleFreqCapability(supported)); } /**---------------------------------------------------------------------------------------- * * void * gatherLinkData(sMainData *pDat, cNorthBridge *nb) * * Description: * For all discovered links, populate the port list with the frequency and width * capabilities. * * Parameters: * @param[in,out] sMainData* pDat = our global state, port list * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void gatherLinkData(sMainData *pDat, cNorthBridge *nb) { u8 i; SBDFO linkBase; u32 temp; for (i = 0; i < pDat->TotalLinks*2; i++) { if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU) { linkBase = makeLinkBase(pDat->PortList[i].NodeID, pDat->PortList[i].Link); pDat->PortList[i].Pointer = linkBase; AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 22, 20, &temp); pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb); AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 18, 16, &temp); pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb); AmdPCIReadBits(linkBase + HTHOST_FREQ_REV_REG, 31, 16, &temp); pDat->PortList[i].PrvFrequencyCap = (u16)temp & 0x7FFF & nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb); /* Mask off bit 15, reserved value */ } else { linkBase = pDat->PortList[i].Pointer; if (pDat->PortList[i].Link == 1) linkBase += HTSLAVE_LINK01_OFFSET; AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp); pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb); AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 18, 16, &temp); pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb); AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 16, &temp); pDat->PortList[i].PrvFrequencyCap = (u16)temp; if (pDat->HtBlock->AMD_CB_DeviceCapOverride) { linkBase &= 0xFFFFF000; AmdPCIRead(linkBase, &temp); pDat->HtBlock->AMD_CB_DeviceCapOverride( pDat->PortList[i].NodeID, pDat->PortList[i].HostLink, pDat->PortList[i].HostDepth, (u8)SBDFO_SEG(pDat->PortList[i].Pointer), (u8)SBDFO_BUS(pDat->PortList[i].Pointer), (u8)SBDFO_DEV(pDat->PortList[i].Pointer), temp, pDat->PortList[i].Link, &(pDat->PortList[i].PrvWidthInCap), &(pDat->PortList[i].PrvWidthOutCap), &(pDat->PortList[i].PrvFrequencyCap)); } } } } /**---------------------------------------------------------------------------------------- * * void * setLinkData(sMainData *pDat, cNorthBridge *nb) * * Description: * Change the hardware state for all links according to the now optimized data in the * port list data structure. * * Parameters: * @param[in] sMainData* pDat = our global state, port list * @param[in] cNorthBridge *nb = this northbridge * * --------------------------------------------------------------------------------------- */ void setLinkData(sMainData *pDat, cNorthBridge *nb) { u8 i; SBDFO linkBase; u32 temp, widthin, widthout, bits; for (i = 0; i < pDat->TotalLinks*2; i++) { ASSERT(pDat->PortList[i&0xFE].SelWidthOut == pDat->PortList[(i&0xFE)+1].SelWidthIn); ASSERT(pDat->PortList[i&0xFE].SelWidthIn == pDat->PortList[(i&0xFE)+1].SelWidthOut); ASSERT(pDat->PortList[i&0xFE].SelFrequency == pDat->PortList[(i&0xFE)+1].SelFrequency); if (pDat->PortList[i].SelRegang) { ASSERT(pDat->PortList[i].Type == PORTLIST_TYPE_CPU); ASSERT(pDat->PortList[i].Link < 4); temp = 1; AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID), makePCIBusFromNode(pDat->PortList[i].NodeID), makePCIDeviceFromNode(pDat->PortList[i].NodeID), CPU_HTNB_FUNC_00, REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link), 0, 0, &temp); } if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU) { if (pDat->HtBlock->AMD_CB_OverrideCpuPort) pDat->HtBlock->AMD_CB_OverrideCpuPort(pDat->PortList[i].NodeID, pDat->PortList[i].Link, &(pDat->PortList[i].SelWidthIn), &(pDat->PortList[i].SelWidthOut), &(pDat->PortList[i].SelFrequency)); } else { if (pDat->HtBlock->AMD_CB_OverrideDevicePort) pDat->HtBlock->AMD_CB_OverrideDevicePort(pDat->PortList[i].NodeID, pDat->PortList[i].HostLink, pDat->PortList[i].HostDepth, pDat->PortList[i].Link, &(pDat->PortList[i].SelWidthIn), &(pDat->PortList[i].SelWidthOut), &(pDat->PortList[i].SelFrequency)); } linkBase = pDat->PortList[i].Pointer; if ((pDat->PortList[i].Type == PORTLIST_TYPE_IO) && (pDat->PortList[i].Link == 1)) linkBase += HTSLAVE_LINK01_OFFSET; /* Some IO devices don't work properly when setting widths, so write them in a single operation, * rather than individually. */ widthout = convertWidthToBits(pDat->PortList[i].SelWidthOut, pDat->nb); ASSERT(widthout == 1 || widthout == 0 || widthout == 5 || widthout == 4); widthin = convertWidthToBits(pDat->PortList[i].SelWidthIn, pDat->nb); ASSERT(widthin == 1 || widthin == 0 || widthin == 5 || widthin == 4); temp = (widthin & 7) | ((widthout & 7) << 4); setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 31, 24, &temp); temp = pDat->PortList[i].SelFrequency; if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU) { ASSERT((temp >= HT_FREQUENCY_600M && temp <= HT_FREQUENCY_2600M) || (temp == HT_FREQUENCY_200M) || (temp == HT_FREQUENCY_400M)); AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, &temp); if (temp > HT_FREQUENCY_1000M) /* Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz */ { /* Enable for Gen3 frequencies */ temp = 1; } else { /* Disable for Gen1 frequencies */ temp = 0; } /* HT3 retry mode enable / disable */ AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID), makePCIBusFromNode(pDat->PortList[i].NodeID), makePCIDeviceFromNode(pDat->PortList[i].NodeID), CPU_HTNB_FUNC_00, REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link), 0, 0, &temp); /* and Scrambling enable / disable */ AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID), makePCIBusFromNode(pDat->PortList[i].NodeID), makePCIDeviceFromNode(pDat->PortList[i].NodeID), CPU_HTNB_FUNC_00, REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link), 3, 3, &temp); } else { SBDFO currentPtr; BOOL isFound; ASSERT(temp <= HT_FREQUENCY_2600M); /* Write the frequency setting */ AmdPCIWriteBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 11, 8, &temp); /* Handle additional HT3 frequency requirements, if needed, * or clear them if switching down to ht1 on a warm reset. * Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz * * Even though we assert if debugging, we need to check that the capability was found * always, since this is an unknown hardware device, also we are taking * unqualified frequency from the call backs * (could be trying to do ht3 on an ht1 IO device). */ if (temp > HT_FREQUENCY_1000M) { /* Enabling features if gen 3 */ bits = 1; } else { /* Disabling features if gen 1 */ bits = 0; } /* Retry Enable */ isFound = FALSE; currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */ do { AmdPCIFindNextCap(¤tPtr); if (currentPtr != ILLEGAL_SBDFO) { AmdPCIRead(currentPtr, &temp); /* HyperTransport Retry Capability? */ if (IS_HT_RETRY_CAPABILITY(temp)) { ASSERT(pDat->PortList[i].Link < 2); AmdPCIWriteBits(currentPtr + HTRETRY_CONTROL_REG, pDat->PortList[i].Link*16, pDat->PortList[i].Link*16, &bits); isFound = TRUE; } /* Some other capability, keep looking */ } else { /* If we are turning it off, that may mean the device was only ht1 capable, * so don't complain that we can't do it. */ if (bits != 0) { if (pDat->HtBlock->AMD_CB_EventNotify) { sHtEventOptRequiredCap evt; evt.eSize = sizeof(sHtEventOptRequiredCap); evt.node = pDat->PortList[i].NodeID; evt.link = pDat->PortList[i].HostLink; evt.depth = pDat->PortList[i].HostDepth; pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING, HT_EVENT_OPT_REQUIRED_CAP_RETRY, (u8 *)&evt); } STOP_HERE; } isFound = TRUE; } } while (!isFound); /* Scrambling enable */ isFound = FALSE; currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */ do { AmdPCIFindNextCap(¤tPtr); if (currentPtr != ILLEGAL_SBDFO) { AmdPCIRead(currentPtr, &temp); /* HyperTransport Gen3 Capability? */ if (IS_HT_GEN3_CAPABILITY(temp)) { ASSERT(pDat->PortList[i].Link < 2); AmdPCIWriteBits((currentPtr + HTGEN3_LINK_TRAINING_0_REG + pDat->PortList[i].Link*HTGEN3_LINK01_OFFSET), 3, 3, &bits); isFound = TRUE; } /* Some other capability, keep looking */ } else { /* If we are turning it off, that may mean the device was only ht1 capable, * so don't complain that we can't do it. */ if (bits != 0) { if (pDat->HtBlock->AMD_CB_EventNotify) { sHtEventOptRequiredCap evt; evt.eSize = sizeof(sHtEventOptRequiredCap); evt.node = pDat->PortList[i].NodeID; evt.link = pDat->PortList[i].HostLink; evt.depth = pDat->PortList[i].HostDepth; pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING, HT_EVENT_OPT_REQUIRED_CAP_GEN3, (u8 *)&evt); } STOP_HERE; } isFound = TRUE; } } while (!isFound); } } } /**---------------------------------------------------------------------------------------- * * void * fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb) * * Description: * Set the command buffer allocations in the buffer count register for the node and link. * The command buffer settings in the low 16 bits are the same on both * family 10h and family 0fh northbridges. * * Parameters: * @param[in] u8 node = The node to set allocations on * @param[in] u8 link = the link to set allocations on * @param[in] u8 req = non-posted Request Command Buffers * @param[in] u8 preq = Posted Request Command Buffers * @param[in] u8 rsp = Response Command Buffers * @param[in] u8 prb = Probe Command Buffers * * --------------------------------------------------------------------------------------- */ static void fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb) { u32 temp; SBDFO currentPtr; currentPtr = makeLinkBase(node, link); currentPtr += HTHOST_BUFFER_COUNT_REG; /* non-posted Request Command Buffers */ temp = req; AmdPCIWriteBits(currentPtr, 3, 0, &temp); /* Posted Request Command Buffers */ temp = preq; AmdPCIWriteBits(currentPtr, 7, 4, &temp); /* Response Command Buffers */ temp = rsp; AmdPCIWriteBits(currentPtr, 11, 8, &temp); /* Probe Command Buffers */ temp = prb; AmdPCIWriteBits(currentPtr, 15, 12, &temp); } /**---------------------------------------------------------------------------------------- * * void * fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD) * * Description: * Set the data buffer allocations in the buffer count register for the node and link. * The command buffer settings in the high 16 bits are not the same on both * family 10h and family 0fh northbridges. * * Parameters: * @param[in] u8 node = The node to set allocations on * @param[in] u8 link = the link to set allocations on * @param[in] u8 reqD = non-posted Request Data Buffers * @param[in] u8 preqD = Posted Request Data Buffers * @param[in] u8 rspD = Response Data Buffers * * --------------------------------------------------------------------------------------- */ static void fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD) { u32 temp; SBDFO currentPtr; currentPtr = makeLinkBase(node, link); currentPtr += HTHOST_BUFFER_COUNT_REG; /* Request Data Buffers */ temp = reqD; AmdPCIWriteBits(currentPtr, 18, 16, &temp); /* Posted Request Data Buffers */ temp = preqD; AmdPCIWriteBits(currentPtr, 22, 20, &temp); /* Response Data Buffers */ temp = rspD; AmdPCIWriteBits(currentPtr, 26, 24, &temp); } /**---------------------------------------------------------------------------------------- * * void * ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb) * * Description: * Set the traffic distribution register for the links provided. * * Parameters: * @param[in] u32 links01 = coherent links from node 0 to 1 * @param[in] u32 links10 = coherent links from node 1 to 0 * @param[in] cNorthBridge* nb = this northbridge * * --------------------------------------------------------------------------------------- */ void ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 temp; /* Node 0 */ /* DstLnk */ AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0), makePCIBusFromNode(0), makePCIDeviceFromNode(0), CPU_HTNB_FUNC_00, REG_HT_TRAFFIC_DIST_0X164), 23, 16, &links01); /* DstNode = 1, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */ temp = 0x0107; AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0), makePCIBusFromNode(0), makePCIDeviceFromNode(0), CPU_HTNB_FUNC_00, REG_HT_TRAFFIC_DIST_0X164), 15, 0, &temp); /* Node 1 */ /* DstLnk */ AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1), makePCIBusFromNode(1), makePCIDeviceFromNode(1), CPU_HTNB_FUNC_00, REG_HT_TRAFFIC_DIST_0X164), 23, 16, &links10); /* DstNode = 0, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */ temp = 0x0007; AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1), makePCIBusFromNode(1), makePCIDeviceFromNode(1), CPU_HTNB_FUNC_00, REG_HT_TRAFFIC_DIST_0X164), 15, 0, &temp); #endif /* HT_BUILD_NC_ONLY */ } /**---------------------------------------------------------------------------------------- * * void * ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb) * * Description: * Traffic distribution is more complex in this case as the routing table must be * adjusted to use one link for requests and the other for responses. Also, * perform the buffer tunings on the links required for this config. * * Parameters: * @param[in] u32 links01 = coherent links from node 0 to 1 * @param[in] u32 links01 = coherent links from node 1 to 0 * @param[in] cNorthBridge* nb = this northbridge * * --------------------------------------------------------------------------------------- */ void ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u32 route01, route10; u8 req0, req1, rsp0, rsp1, nclink; /* * Get the current request route for 0->1 and 1->0. This will indicate which of the links * in links01 are connected to which links in links10. Since we have to route to distribute * traffic, we need to know that. The link used by htinit will become the request, probe link. * the other link will be used for responses. */ /* Get the routes, and hang on to them, we will write them back updated. */ AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(0), makePCIBusFromNode(0), makePCIDeviceFromNode(0), CPU_HTNB_FUNC_00, REG_ROUTE1_0X44), &route01); AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(1), makePCIBusFromNode(1), makePCIDeviceFromNode(1), CPU_HTNB_FUNC_00, REG_ROUTE0_0X40), &route10); /* Convert the request routes to a link number. Note "0xE" is ht1 nb specific. * Find the response link numbers. */ ASSERT((route01 & 0xE) && (route10 & 0xE)); /* no route! error! */ req0 = (u8)AmdBitScanReverse((route01 & 0xE)) - 1; req1 = (u8)AmdBitScanReverse((route10 & 0xE)) - 1; /* Now, find the other link for the responses */ rsp0 = (u8)AmdBitScanReverse((links01 & ~((u32)1 << req0))); rsp1 = (u8)AmdBitScanReverse((links10 & ~((u32)1 << req1))); /* ht1 nb restriction, must have exactly two links */ ASSERT(((((links01 & ~((u32)1 << req0)) & ~((u32)1 << rsp0))) == 0) && ((((links10 & ~((u32)1 << req1)) & ~((u32)1 << rsp1))) == 0)); route01 = (route01 & ~0x0E00) | ((u32)0x0100<<(rsp0 + 1)); route10 = (route10 & ~0x0E00) | ((u32)0x0100<<(rsp1 + 1)); AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(0), makePCIBusFromNode(0), makePCIDeviceFromNode(0), CPU_HTNB_FUNC_00, REG_ROUTE1_0X44), &route01); AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(1), makePCIBusFromNode(1), makePCIDeviceFromNode(1), CPU_HTNB_FUNC_00, REG_ROUTE0_0X40), &route10); /* While we otherwise do buffer tunings elsewhere, for the dual cHT DP case with * ht1 northbridges like family 0Fh, do the tunings here where we have all the * link and route info at hand and don't need to recalculate it. */ /* Node 0, Request / Probe Link (note family F only has links < 4) */ fam0fWriteHTLinkCmdBufferAlloc(0, req0, 6, 3, 1, 6); fam0fWriteHTLinkDatBufferAlloc(0, req0, 4, 3, 1); /* Node 0, Response Link (note family F only has links < 4) */ fam0fWriteHTLinkCmdBufferAlloc(0, rsp0, 1, 0, 15, 0); fam0fWriteHTLinkDatBufferAlloc(0, rsp0, 1, 1, 6); /* Node 1, Request / Probe Link (note family F only has links < 4) */ fam0fWriteHTLinkCmdBufferAlloc(1, req1, 6, 3, 1, 6); fam0fWriteHTLinkDatBufferAlloc(1, req1, 4, 3, 1); /* Node 1, Response Link (note family F only has links < 4) */ fam0fWriteHTLinkCmdBufferAlloc(1, rsp1, 1, 0, 15, 0); fam0fWriteHTLinkDatBufferAlloc(1, rsp1, 1, 1, 6); /* Node 0, is the third link non-coherent? */ nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req0) & ~((u32)1 << rsp0))); if (nb->verifyLinkIsNonCoherent(0, nclink, nb)) { fam0fWriteHTLinkCmdBufferAlloc(0, nclink, 6, 5, 2, 0); } /* Node 1, is the third link non-coherent? */ nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req1) & ~((u32)1 << rsp1))); if (nb->verifyLinkIsNonCoherent(1, nclink, nb)) { fam0fWriteHTLinkCmdBufferAlloc(1, nclink, 6, 5, 2, 0); } #endif /* HT_BUILD_NC_ONLY */ } /**---------------------------------------------------------------------------------------- * * void * fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb) * * Description: * Buffer tunings are inherently northbridge specific. Check for specific configs * which require adjustments and apply any standard workarounds to this node. * * Parameters: * @param[in] u8 node = the node to * @param[in] sMainData *pDat = coherent links from node 0 to 1 * @param[in] cNorthBridge* nb = this northbridge * * --------------------------------------------------------------------------------------- */ void fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb) { #ifndef HT_BUILD_NC_ONLY u8 i; u32 temp; SBDFO currentPtr; ASSERT(node < nb->maxNodes); /* Fix the FIFO pointer register before changing speeds */ currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_FIFOPTR_3XDC); for (i=0; i < nb->maxLinks; i++) { temp = 0; if (nb->verifyLinkIsCoherent(node, i, nb)) { temp = 0x26; ASSERT(i<3); AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp); } else { if (nb->verifyLinkIsNonCoherent(node, i, nb)) { temp = 0x25; ASSERT(i<3); AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp); } } } /* * 8P Buffer tuning. * Either apply the BKDG tunings or, if applicable, apply the more restrictive errata 153 * workaround. * If 8 nodes, Check this node for 'inner' or 'outer'. * Tune each link based on coherent or non-coherent */ if (pDat->NodesDiscovered >= 6) { u8 j; BOOL isOuter; BOOL isErrata153; /* This is for family 0Fh, so assuming dual core max then 7 or 8 nodes are required * to be in the situation of 14 or more cores. We checked nodes above, cross check * that the number of cores is 14 or more. We want both 14 cores with at least 7 or 8 nodes * not one condition alone, to apply the errata 153 workaround. Otherwise, 7 or 8 rev F * nodes use the BKDG tuning. */ isErrata153 = 0; AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(0), makePCIBusFromNode(0), makePCIDeviceFromNode(0), CPU_HTNB_FUNC_00, REG_NODE_ID_0X60), 19, 16, &temp); if (temp >= 14) { /* Check whether we need to do errata 153 tuning or BKDG tuning. * Errata 153 applies to JH-1, JH-2 and older. It is fixed in JH-3 * (and, one assumes, from there on). */ for (i=0; i < (pDat->NodesDiscovered +1); i++) { AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(i), makePCIBusFromNode(i), makePCIDeviceFromNode(i), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC), 7, 0, &temp); if (((u8)temp & ~0x40) < 0x13) { isErrata153 = 1; break; } } } for (i=0; i < CPU_ADDR_NUM_CONFIG_MAPS; i++) { isOuter = FALSE; /* Check for outer node by scanning the config maps on node 0 for one * which is assigned to this node. */ currentPtr = MAKE_SBDFO(makePCISegmentFromNode(0), makePCIBusFromNode(0), makePCIDeviceFromNode(0), CPU_ADDR_FUNC_01, REG_ADDR_CONFIG_MAP0_1XE0 + (4 * i)); AmdPCIReadBits (currentPtr, 1, 0, &temp); /* Make sure this config map is valid, if it is it will be enabled for read/write */ if (temp == 3) { /* It's valid, get the node (that node is an outer node) */ AmdPCIReadBits (currentPtr, 6, 4, &temp); /* Is the node we're working on now? */ if (node == (u8)temp) { /* This is an outer node. Tune it appropriately. */ for (j=0; j < nb->maxLinks; j++) { if (isErrata153) { if (nb->verifyLinkIsCoherent(node, j, nb)) { fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 6, 4); } else { if (nb->verifyLinkIsNonCoherent(node, j, nb)) { fam0fWriteHTLinkCmdBufferAlloc(node, j, 5, 4, 1, 0); } } } else { if (nb->verifyLinkIsCoherent(node, j, nb)) { fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 8, 5); } } } /* * SRI to XBAR Buffer Counts are correct for outer node at power on defaults. */ isOuter = TRUE; break; } } /* We fill config maps in ascending order, so if we didn't use this one, we're done. */ else break; } if (!isOuter) { if (isErrata153) { /* Tuning for inner node coherent links */ for (j=0; j < nb->maxLinks; j++) { if (nb->verifyLinkIsCoherent(node, j, nb)) { fam0fWriteHTLinkCmdBufferAlloc(node, j, 2, 1, 5, 4); } } /* SRI to XBAR Buffer Count for inner nodes, zero DReq and DPReq */ temp = 0; AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_SRI_XBAR_BUF_3X70), 31, 28, &temp); } } /* * Tune MCT to XBAR Buffer Count the same an all nodes, 2 Probes, 5 Response */ if (isErrata153) { temp = 0x25; AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_MCT_XBAR_BUF_3X78), 14, 8, &temp); } } #endif /* HT_BUILD_NC_ONLY */ } /**---------------------------------------------------------------------------------------- * * void * fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb) * * Description: * Buffer tunings are inherently northbridge specific. Check for specific configs * which require adjustments and apply any standard workarounds to this node. * * Parameters: * @param[in] u8 node = the node to tune * @param[in] sMainData *pDat = global state * @param[in] cNorthBridge* nb = this northbridge * * --------------------------------------------------------------------------------------- */ void fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb) { u32 temp; SBDFO currentPtr; u8 i; ASSERT(node < nb->maxNodes); /* * Link to XCS Token Count Tuning * * For each active link that we reganged (so this unfortunately can't go into the PCI reg * table), we have to switch the Link to XCS Token Counts to the ganged state. * We do this here for the non-uma case, which is to write the values that would have * been power on defaults if the link was ganged at cold reset. */ for (i = 0; i < pDat->TotalLinks*2; i++) { if ((pDat->PortList[i].NodeID == node) && (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)) { /* If the link is greater than 4, this is a sublink 1, so it is not reganged. */ if (pDat->PortList[i].Link < 4) { currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_LINK_XCS_TOKEN0_3X148 + 4*pDat->PortList[i].Link); if (pDat->PortList[i].SelRegang) { /* Handle all the regang Token count adjustments */ /* Sublink 0: [Probe0tok] = 2 [Rsp0tok] = 2 [PReq0tok] = 2 [Req0tok] = 2 */ temp = 0xAA; AmdPCIWriteBits(currentPtr, 7, 0, &temp); /* Sublink 1: [Probe1tok] = 0 [Rsp1tok] = 0 [PReq1tok] = 0 [Req1tok] = 0 */ temp = 0; AmdPCIWriteBits(currentPtr, 23, 16, &temp); /* [FreeTok] = 3 */ temp = 3; AmdPCIWriteBits(currentPtr, 15, 14, &temp); } else { /* Read the regang bit in hardware */ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID), makePCIBusFromNode(pDat->PortList[i].NodeID), makePCIDeviceFromNode(pDat->PortList[i].NodeID), CPU_HTNB_FUNC_00, REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link), 0, 0, &temp); if (temp == 1) { /* handle a minor adjustment for stapped ganged links. If SelRegang is false we * didn't do the regang, so if the bit is on then it's hardware strapped. */ /* [FreeTok] = 3 */ temp = 3; AmdPCIWriteBits(currentPtr, 15, 14, &temp); } } } } } } /* * North Bridge 'constructor'. * */ /**---------------------------------------------------------------------------------------- * * void * newNorthBridge(u8 node, cNorthBridge *nb) * * Description: * 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. * * Parameters: * @param[in] node u8 = create a northbridge interface for this node. * @param[out] cNorthBridge* nb = the caller's northbridge structure to initialize. * * --------------------------------------------------------------------------------------- */ void newNorthBridge(u8 node, cNorthBridge *nb) { u32 match; u32 extFam, baseFam, model; cNorthBridge fam10 = { #ifdef HT_BUILD_NC_ONLY 8, 1, 12, #else 8, 8, 64, #endif /* HT_BUILD_NC_ONLY*/ writeRoutingTable, writeNodeID, readDefLnk, enableRoutingTables, verifyLinkIsCoherent, readTrueLinkFailStatus, readToken, writeToken, fam10GetNumCoresOnNode, setTotalNodesAndCores, limitNodes, writeFullRoutingTable, isCompatible, fam10IsCapable, (void (*)(u8, u8, cNorthBridge*))commonVoid, (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse, readSbLink, verifyLinkIsNonCoherent, ht3SetCFGAddrMap, convertBitsToWidth, convertWidthToBits, fam10NorthBridgeFreqMask, gatherLinkData, setLinkData, ht3WriteTrafficDistribution, fam10BufferOptimizations, 0x00000001, 0x00000200, 18, 0x00000f01 }; cNorthBridge fam0f = { #ifdef HT_BUILD_NC_ONLY 3, 1, 12, #else 3, 8, 32, #endif /* HT_BUILD_NC_ONLY*/ writeRoutingTable, writeNodeID, readDefLnk, enableRoutingTables, verifyLinkIsCoherent, readTrueLinkFailStatus, readToken, writeToken, fam0FGetNumCoresOnNode, setTotalNodesAndCores, limitNodes, writeFullRoutingTable, isCompatible, fam0fIsCapable, fam0fStopLink, (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse, readSbLink, verifyLinkIsNonCoherent, ht1SetCFGAddrMap, convertBitsToWidth, convertWidthToBits, ht1NorthBridgeFreqMask, gatherLinkData, setLinkData, ht1WriteTrafficDistribution, fam0fBufferOptimizations, 0x00000001, 0x00000100, 16, 0x00000f00 }; /* Start with enough of the key to identify the northbridge interface */ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC), 27, 20, &extFam); AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC), 11, 8, &baseFam); AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node), makePCIBusFromNode(node), makePCIDeviceFromNode(node), CPU_NB_FUNC_03, REG_NB_CPUID_3XFC), 7, 4, &model); match = (u32)((baseFam << 8) | extFam); /* Test each in turn looking for a match. Init the struct if found */ if (match == fam10.compatibleKey) { Amdmemcpy((void *)nb, (const void *)&fam10, (u32) sizeof(cNorthBridge)); } else { if (match == fam0f.compatibleKey) { Amdmemcpy((void *)nb, (const void *)&fam0f, (u32) sizeof(cNorthBridge)); } else { STOP_HERE; } } /* Update the initial limited key to the real one, which may include other matching info */ nb->compatibleKey = makeKey(node); }