blob: cba21b33497d2d1c89cb8593629cbef12ccb65b0 [file] [log] [blame]
/*
* 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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.
*
* ---------------------------------------------------------------------------------------
*/
static 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;
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static BOOL
* 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
*
* ---------------------------------------------------------------------------------------
*/
static 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 */
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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;
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
{
u32 temp, leveling, cores;
u8 i;
ASSERT((node < nb->maxNodes));
/* Read CmpCap [2][1:0] */
AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
makePCIBusFromNode(node),
makePCIDeviceFromNode(node),
CPU_NB_FUNC_03,
REG_NB_CAPABILITY_3XE8),
15, 12, &temp);
/* bits[15,13,12] specify the cores */
/* Support Downcoring */
temp = ((temp & 8) >> 1) + (temp & 3);
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; i<cores; i++)
{
if (leveling & ((u32) 1 << i))
{
temp--;
}
}
return (u8)(temp+1);
}
/**----------------------------------------------------------------------------------------
*
* static void
* setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
*
* Description:
* Write the total number of cores and nodes to the node
*
* Parameters:
* @param[in] u8 node = the node that will be examined
* @param[in] u8 totalNodes = the total number of nodes
* @param[in] u8 totalCores = the total number of cores
* @param[in] cNorthBridge *nb = this northbridge
*
* ---------------------------------------------------------------------------------------
*/
static void setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
{
SBDFO nodeIDReg;
u32 temp;
ASSERT((node < nb->maxNodes) && (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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static BOOL isCompatible(u8 node, cNorthBridge *nb)
{
return (makeKey(node) == nb->compatibleKey);
}
/**----------------------------------------------------------------------------------------
*
* static 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.
*
* ---------------------------------------------------------------------------------------
*/
static 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
}
/**----------------------------------------------------------------------------------------
*
* static 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.
*
* ---------------------------------------------------------------------------------------
*/
static 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
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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
}
/**----------------------------------------------------------------------------------------
*
* static void
* commonVoid()
*
* Description:
* Nothing.
*
* Parameters:
* None.
*
* ---------------------------------------------------------------------------------------
*/
static void commonVoid(void)
{
}
/**----------------------------------------------------------------------------------------
*
* static BOOL
* commonReturnFalse()
*
* Description:
* Return False.
*
* Parameters:
* @param[out] BOOL result = false
* ---------------------------------------------------------------------------------------
*/
static BOOL commonReturnFalse(void)
{
return 0;
}
/***************************************************************************
*** Non-coherent init code ***
*** Northbridge access routines ***
***************************************************************************/
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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;
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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;
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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 ***
***************************************************************************/
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static u8 convertBitsToWidth(u8 value, cNorthBridge *nb)
{
switch(value) {
case 1: return 16;
case 0: return 8;
case 5: return 4;
case 4: return 2;
default: STOP_HERE; /* This is an error internal condition */
}
return 0; // shut up GCC.
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static u8 convertWidthToBits(u8 value, cNorthBridge *nb)
{
switch (value) {
case 16: return 1;
case 8: return 0;
case 4: return 5;
case 2: return 4;
default: STOP_HERE; /* This is an internal error condition */
}
return 0; // shut up GCC
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static u16 ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
{
/* only up to HT1 speeds */
return (HT_FREQUENCY_LIMIT_HT1_ONLY);
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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));
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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));
}
}
}
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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(&currentPtr);
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(&currentPtr);
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
*
* ---------------------------------------------------------------------------------------
*/
#ifndef HT_BUILD_NC_ONLY
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);
}
#endif /* HT_BUILD_NC_ONLY */
/**----------------------------------------------------------------------------------------
*
* 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
*
* ---------------------------------------------------------------------------------------
*/
#ifndef HT_BUILD_NC_ONLY
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);
}
#endif /* HT_BUILD_NC_ONLY */
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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 */
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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 */
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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 */
}
/**----------------------------------------------------------------------------------------
*
* static 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
*
* ---------------------------------------------------------------------------------------
*/
static 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);
}