diff options
author | Marc Jones <marc.jones@amd.com> | 2007-12-19 01:32:08 +0000 |
---|---|---|
committer | Marc Jones <marc.jones@amd.com> | 2007-12-19 01:32:08 +0000 |
commit | 8ae8c8822068ef1722c08073ffa4ecc25633cbee (patch) | |
tree | 8c7bbf2f7b791081e486439a9b7ffb2fd6e649ac /src/northbridge/amd/amdht | |
parent | 2006b38fed2f5f3680de1736f7fc878823f2f93b (diff) | |
download | coreboot-8ae8c8822068ef1722c08073ffa4ecc25633cbee.tar.xz |
Initial AMD Barcelona support for rev Bx.
These are the core files for HyperTransport, DDR2 Memory, and multi-core initialization.
Signed-off-by: Marc Jones <marc.jones@amd.com>
Reviewed-by: Jordan Crouse <jordan.crouse@amd.com>
Acked-by: Myles Watson <myles@pel.cs.byu.edu>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3014 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/amd/amdht')
-rw-r--r-- | src/northbridge/amd/amdht/AsPsDefs.h | 252 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/AsPsNb.c | 145 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/AsPsNb.h | 26 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/comlib.c | 290 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/comlib.h | 59 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3ffeat.h | 177 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3finit.c | 1678 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3finit.h | 613 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3gtopo.h | 358 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3ncmn.c | 2214 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3ncmn.h | 132 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/ht_wrapper.c | 160 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/porting.h | 88 |
13 files changed, 6192 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdht/AsPsDefs.h b/src/northbridge/amd/amdht/AsPsDefs.h new file mode 100644 index 0000000000..2a5a908c71 --- /dev/null +++ b/src/northbridge/amd/amdht/AsPsDefs.h @@ -0,0 +1,252 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + + +#ifndef ASPSDEFS_H +#define ASPSDEFS_H + +/* AMD Platform Types */ +#define AMD_PTYPE_DSK 1 +#define AMD_PTYPE_MOB 2 +#define AMD_PTYPE_SVR 4 +#define AMD_PTYPE_DC 8 +#define AMD_PTYPE_MC 0x10 +#define AMD_PTYPE_UMA 0x20 + +#define APIC_BAR 0x1b /* APIC_BAR register */ +#define APIC_BAR_BP 0x100 /* APIC_BAR BSP bit */ + +#define PS_LIM_REG 0xC0010061 /* P-state Current Limit Register */ +#define PS_CUR_LIM_SHFT 4 /* P-state Current Limit shift position */ + +#define PS_CTL_REG 0xC0010062 /* P-state Control Register */ +#define PS_CMD_MASK_OFF 0xfffffff8 /* P-state Control Register CMD Mask OFF */ + +#define PS_STS_REG 0xC0010063 /* P-state Status Register */ +#define PS_STS_MASK 0x7 /* P-state Status Mask */ + +#define PS_REG_BASE 0xC0010064 /* P-state Register base */ +#define PS_MAX_REG 0xC0010068 /* Maximum P-State Register */ +#define PS_MIN_REG 0xC0010064 /* Mimimum P-State Register */ + +/* P-state register offset */ +#define PS_REG0 0 /* offset for P0 */ +#define PS_REG1 1 /* offset for P1 */ +#define PS_REG2 2 /* offset for P2 */ +#define PS_REG3 3 /* offset for P3 */ +#define PS_REG4 4 /* offset for P4 */ + +#define PS_PSDIS_MASK 0x7fffffff /* disable P-state register */ +#define PS_EN_MASK 0x80000000 /* P-state register enable mask */ +#define PS_NB_DID_MASK 0x400000 /* P-state Reg[NbDid] Mask */ +#define PS_NB_VID_M_OFF 0x01ffffff /* P-state Reg[NbVid] Mask OFF */ +#define PS_CPU_VID_M_ON 0x0fe00 /* P-state Reg[CpuVid] Mask On */ +#define PS_NB_VID_M_ON 0x0fe000000 /* P-state Reg[NbVid] Mask On */ +#define PS_CPU_VID_SHFT 9 /* P-state bit shift for CpuVid */ +#define PS_NB_VID_SHFT 25 /* P-state bit shift for NbVid */ +#define PS_BOTH_VID_OFF 0x01ff01ff /* Mask NbVid & CpuVid */ +#define PS_CPU_NB_VID_SHFT 16 /* P-state bit shift from CpuVid to NbVid */ +#define PS_NB_VID_SHFT 25 /* P-state NBVID shift */ +#define PS_DIS 0x7fffffff /* disable P-state reg */ +#define PS_EN 0x80000000 /* enable P-state reg */ +#define PS_CURDIV_SHFT 8 /* P-state Current Divisor shift position */ +#define PS_CPUDID_SHIFT 6 /* P-state CPU DID shift position */ + +/* for unfused parts */ +#define PS_NB_VID_110V 0x48000000 +#define PS_NB_VID_1175V 0x3c000000 +/* NB VID 1.100V =0x12[PVI]=0x24[SVI] = 0100100b 7-bit code */ + +#define PS_NB_DID0 0 /* NB DID 0 */ +#define PS_NB_DID1 0x400000 /* NB DID 1 */ +#define PS_CPU_VID_110V 0x4800 /* CPU VID 1.100V */ +#define PS_CPU_VID_1175V 0x3c00 /* CPU VID 1.175V */ +#define PS_CPU_DID 0x40 /* CPU DID 1 = divisor of 2 */ +#define PS_CPU_DID0 0 /* CPU DID 0 = divisor of 1 */ +#define PS_CPU_FID_16G 0x00 /* CPU FID of 00 = 1.6GHz */ +#define PS_CPU_FID_16G1 0x10 /* CPU FId of 16 COF = 16+16/2 = 16 */ +#define PS_CPU_FID_18G 20 /* CPU FId of 20 COF = 20+16/2 = 18 */ +#define PS_CPU_FID_19G 22 /* CPU FId of 20 COF = 22+16/2 = 19 */ +#define PS_CPU_FID_20G 24 /* CPU FId of 20 COF = 24+16/2 = 20 */ +#define PS_CPU_FID_22G 28 /* CPU FId of 2C COF = 28+16/2 = 22 */ +#define PS_CPU_FID_30G 44 /* CPU FId of 2C COF = 44+16/2 = 30 */ + + + +#define PCI_DEV_BASE 24 /* System PCI device ID base */ +#define LOCAL_APIC_ID_SHIFT 24 /* Local APCI ID shift bit # */ +#define APIC_CID_SIZE_SHIFT 12 /* ApicCoreIdSize shift bit # */ +#define FN_0 0 /* Function 0 */ +#define FN_1 1 /* Function 1 */ +#define FN_2 2 /* Function 2 */ +#define FN_3 3 /* Function 3 */ +#define FN_4 4 /* Function 4 */ +#define FN_5 5 /* Function 5 */ +#define FN_80000000 0x80000000 /* Function 8000_0000 */ +#define FN_80000001 0x80000001 /* Function 8000_0001 */ +#define FN_80000008 0x80000008 /* Function 8000_0008 */ + +#define LNK_INIT_REG 0x6C /* F0x6C link initialization control register */ +#define WARM_RESET_BIT 0x10 /* bit 4 =1 : warm reset */ + +#define HTC_REG 0x64 /* hardware thermal control reg */ +#define HTC_PS_LMT_MASK 0x8fffffff /* HtcPstateLimit mask off */ +#define PS_LIMIT_POS 28 /* PstateLimit position for HTC & STC */ + +#define STC_REG 0x68 /* software thermal control reg */ +#define STC_PS_LMT_MASK 0x8fffffff /* StcPstateLimit mask off */ + +#define CPTC0 0x0d4 /* Clock Power/Timing Control0 Register*/ +#define CPTC0_MASK 0x000c0fff /* Reset mask for this register */ +#define CPTC0_NBFID_MASK 0xffffffe0 /* NbFid mask off for this register */ +#define CPTC0_NBFID_MON 0x1f /* NbFid mask on for this register */ +#define NB_FID_EN 0x20 /* NbFidEn bit ON */ +#define NB_CLKDID_ALL 0x80000000 /* NbClkDidApplyAll bit ON */ +#define NB_CLKDID 0x40000000 /* NbClkDid value set by BIOS */ +#define PW_STP_UP50 0x08000000 /* PowerStepUp 50nS(1000b) */ +#define PW_STP_DN50 0x00800000 /* PowerStepDown 50nS (1000b)*/ +#define PW_STP_UP100 0x03000000 /* PowerStepUp 100nS(0011b) */ +#define PW_STP_DN100 0x00300000 /* PowerStepDown 100nS (0011b)*/ +#define PW_STP_UP200 0x02000000 /* PowerStepUp 200nS(0010b) */ +#define PW_STP_DN200 0x00200000 /* PowerStepDown 200nS (0010b)*/ +#define PW_STP_UP400 0x00000000 /* PowerStepUp 400nS(0000b) */ +#define PW_STP_DN400 0x00000000 /* PowerStepDown 400nS (0000b)*/ + + +#define LNK_PLL_LOCK 0x00010000 /* LnkPllLock value set (01b) by BIOS */ + + + +#define PSTATE_CTL 0xC0010070 /* P-state Control Register */ +#define NB_VID_POS 25 /* NbVid bit shift for position */ +#define NB_VID_MASK_OFF 0x01ffffff /* NbVid bits mask off */ +#define NB_VID_MASK_ON 0xfe000000 /* NbVid bits mask on */ +#define CPU_VID_POS 0x9 /* CpuVid bit shift for position */ +#define CPU_VID_MASK_OFF 0xffff01ff /* CpuVid bits mask off */ +#define CPU_VID_MASK_ON 0x0000fe00 /* CpuVid bits mask on */ +#define CPU_FID_DID_M_ON 0x000001ff /* CpuFid & CpuDid mask on */ +#define CPU_FID_DID_M_OFF 0xfffffe00 /* CpuFid & CpuDid mask off */ +#define NB_DID_VID_M_ON 0xfe400000 /* NbDid & NbVid mask on */ +#define NB_DID_M_ON 0x00400000 /* NbDid mask on */ +#define NB_DID_M_OFF 0xffbfffff /* NbDid mask off */ +#define NB_DID_POS 22 /* NbDid bit shift for position */ +#define PS_M_OFF 0xfff8ffff /* Cur Pstate mask off */ +#define PS_1 0x00010000 /* P-state 1 */ +#define PS_2 0x00020000 /* P-state 2 */ +#define PS_CPU_DID_1 0x40 /* Cpu Did 1 */ + + + + +#define PSTATE_STS 0xC0010071 /* P-state Status Register */ +#define STARTUP_PS_MASK 0x7 /* StartupPstate Mask */ + +/* define for NB VID & CPU VID transition functions */ +#define IS_NB 1 +#define IS_CPU 0 + +/* F3xD8 Clock Power/Timing Control 1 Register */ +#define CPTC1 0xd8 /* Clock Power/Timing Control1 Register*/ +#define VSRAMP_SLAM_MASK 0xffffff88 /* MaskOff [VSRampTime]&[VSSlamTime] */ +#define VSRAMP_SLAM_VALUE 0x16 /* [VSRampTime]=001b&[VSSlamTime]=110b */ +#define VS_RAMP_T 4 /* VSRampTime bit position */ +#define PWR_PLN_SHIFT 28 /* PwrPlanes bit shift */ +#define PWR_PLN_ON 0x10000000 /* PwrPlanes bit ON */ +#define PWR_PLN_OFF 0x0efffffff /* PwrPlanes bit OFF */ + + + +/* Northbridge Capability Register */ +#define NB_CAP 0xe8 /* Northbridge Cap Reg */ +#define CMP_CAP_SHFT 12 /* CMP CAP - number of enabled cores */ + +/* F3xDC Clock Power/Timing Control 2 Register */ +#define CPTC2 0xdc /* Clock Power/Timing Control2 Register*/ +#define PS_MAX_VAL_POS 8 /* PstateMaxValue bit shift */ +#define PS_MAX_VAL_MASK 0xfffff8ff /* PstateMaxValue Mask off */ + +#define PRCT_INFO 0x1fc /* Product Info Register */ +#define UNI_NB_FID_BIT 2 /* UniNbFid bit position */ +#define UNI_NB_VID_BIT 7 /* UniNbVid bit position */ +#define SPLT_NB_FID_OFFSET 14 /* SpltNbFidOffset value bit position */ +#define SPLT_NB_VID_OFFSET 17 /* SpltNbVidOffset value bit position */ +#define NB_CV_UPDATE 0x01 /* F3x1FC[NbCofVidUpdated] bit mask */ +#define NB_VID_UPDATE_ALL 0x02 /* F3x1FC[NbVidUpdatedAll] bit mask */ +#define C_FID_DID_M_OFF 0xfffffe00 /* mask off Core FID & DID */ + +#define PW_CTL_MISC 0x0a0 /* Power Control Miscellaneous Register */ +#define COF_VID_PROG_BIT 0x80000000 /* CofVidProg bit. 0= unfused part */ +#define DUAL_VDD_BIT 0x40000000 /* DualVdd bit. */ +#define NB_COFVID_UPDATE_BIT 0x01 /* NbCOFVIDUpdated bit */ +#define PVI_MODE 0x100 /* PviMode bit mask */ +#define VID_SLAM_OFF 0x0dfffffff /* set VidSlamMode OFF */ +#define VID_SLAM_ON 0x020000000 /* set VidSlamMode ON */ +#define PLLLOCK_OFF 0x0ffffc7ff /* PllLockTime Mask OFF */ +#define PLLLOCK_DFT 0x00001800 /* PllLockTime default value = 011b */ +#define PLLLOCK_DFT_L 0x00002800 /* PllLockTime long value = 101b */ + +/* P-state Specification register base in PCI sapce */ +#define PS_SPEC_REG 0x1e0 /* PS Spec register base address */ +#define PCI_REG_LEN 4 /* PCI register length */ +#define NB_DID_MASK 0x10000 /* NbDid bit mask */ +#define NB_DID_2 2 /* NbDid = 2 */ +#define NB_DID_1 1 /* NbDid = 1 */ +#define SPEC_PWRDIV_M_ON 0x06000000 /* PwrDiv mask on */ +#define SPEC_PWRVAL_M_ON 0x01e00000 /* PwrValue mask on */ +#define SPEC_PWRDIV_SHFT 25 /* PwrDiv shift */ +#define SPEC_PWRVAL_SHFT 17 /* PwrValue shift */ + +/* F4x1F4 Northbridge P-state spec register */ +#define NB_PS_SPEC_REG 0x1f4 /* Nb PS spec reg */ + +#define NM_PS_REG 5 /* number of P-state MSR registers */ + +/* sFidVidInit.outFlags defines */ +#define PWR_CK_OK 0 /* System board check OK */ +#define PWR_CK_NO_PS 1 /* All P-state registers are over + the limit */ + +/* bit mask */ +#define BIT_MASK_1 0x1 +#define BIT_MASK_2 0x3 +#define BIT_MASK_3 0x7 +#define BIT_MASK_4 0x0f +#define BIT_MASK_5 0x1f +#define BIT_MASK_6 0x3f +#define BIT_MASK_7 0x7f +#define BIT_MASK_8 0x0ff + +/* VID Code */ +#define VID_1_100V 0x12 /* 1.100V */ +#define VID_1_175V 0x1E /* 1.175V */ + + +/* Nb Fid Code */ +#define NB_FID_800M 0x00 /* 800MHz */ + +/* Nb DID Code */ +#define NB_DID_0 0 +#define NB_DID_1 1 + +/* GH Logical ID */ + +#define GH_REV_A2 0x4 /* GH Rev A2 logical ID, Upper half */ + + +#endif diff --git a/src/northbridge/amd/amdht/AsPsNb.c b/src/northbridge/amd/amdht/AsPsNb.c new file mode 100644 index 0000000000..8f79cd107f --- /dev/null +++ b/src/northbridge/amd/amdht/AsPsNb.c @@ -0,0 +1,145 @@ +/* + * This file is part of the LinuxBIOS 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 0xCCCC +#include "comlib.h" +#include "AsPsDefs.h" +#include "AsPsNb.h" + + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ +u8 getNumOfNodeNb(void); +u8 translateNodeIdToDeviceIdNb(u8 nodeId); + + +/*---------------------------------------------------------------------------- + * FUNCTION: getMinNbCOF + * INPUT: None + * OUTPUT: minNbCOF (in multiple of half of CLKIN, 100MHz) + * DESCRIPTION: + * This function returns the minimum possible NbCOF (in 100MHz) + * for the system . + * This function can be run on any core and is used by the HT & Memory init code + * in Phase 1. + * ---------------------------------------------------------------------------- + */ +u8 getMinNbCOF(void) +{ + u8 numOfNode, i, j, deviceId, nbDid, nbFid, nextNbFid; + u32 dtemp; + + nbDid = 0; + nbFid = 0; + + /* get number of node in the system */ + numOfNode = getNumOfNodeNb(); + + /* go through each node for the minimum NbCOF (in multiple of CLKIN/2) */ + for(i=0; i < numOfNode; i++) + { + /* stub function for APIC ID virtualization for large MP system later */ + deviceId = translateNodeIdToDeviceIdNb(i); + + /* read all P-state spec registers for NbDid=1 */ + for(j=0; j < 5; j++) + { + AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_4,PS_SPEC_REG+(j*PCI_REG_LEN)), &dtemp); /*F4x1E0 + j*4 */ + /* get NbDid */ + if(dtemp & NB_DID_MASK) + nbDid = 1; + } + /* if F3x1FC[NbCofVidUpdate]=0, NbFid = default value */ + AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PRCT_INFO), &dtemp); /*F3x1FC*/ + if(!(dtemp & NB_CV_UPDATE)) /* F3x1FC[NbCofVidUpdated]=0, use default VID */ + { + AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,CPTC0), &dtemp); /*F3xD4*/ + nextNbFid = (u8) (dtemp & BIT_MASK_5); + if(nbDid) + nextNbFid = (u8) (nextNbFid >> 1); + } + else + { + /* check PVI/SPI */ + AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PW_CTL_MISC), &dtemp); /*F3xA0*/ + if(dtemp & PVI_MODE) /* PVI */ + { + AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PRCT_INFO), &dtemp); /*F3x1FC*/ + nextNbFid = (u8) (dtemp >> UNI_NB_FID_BIT); + nextNbFid &= BIT_MASK_5; + /* if(nbDid) + nextNbFid = nextNbFid >> 1; */ + } + else /* SVI */ + { + AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PRCT_INFO), &dtemp); /*F3x1FC*/ + nextNbFid = (u8) ((dtemp >> UNI_NB_FID_BIT) & BIT_MASK_5); + nextNbFid = (u8) (nextNbFid + ((dtemp >> SPLT_NB_FID_OFFSET) & BIT_MASK_3)); + /* if(nbDid) + nextNbFid = nextNbFid >> 1; */ + } + } + if( i == 0) + nbFid = nextNbFid; + else if( nbFid > nextNbFid ) + nbFid = nextNbFid; + } + + /* add the base and convert to 100MHz divide by 2 if DID=1 */ + if(nbDid) + nbFid = (u8) (nbFid + 4); + else + nbFid = (u8) ((nbFid + 4) << 1); + return nbFid; +} + +u8 getNumOfNodeNb(void) +{ + u32 dtemp; + + AmdPCIRead(MAKE_SBDFO(0,0,24,0,0x60), &dtemp); + dtemp = (dtemp >> 4) & BIT_MASK_3; + dtemp++; + return (u8)dtemp; +} + +/*---------------------------------------------------------------------------- + * FUNCTION: translateNodeIdToDeviceId + * INPUT: u8 nodeId - node ID of the node + * OUTPUT: u8 - PCI device ID of the node + * DESCRIPTION: + * This function return the PCI device ID for PCI access using node ID. + * This function may need to chnage node ID to device ID in big MP systems. + * ---------------------------------------------------------------------------- + */ +u8 translateNodeIdToDeviceIdNb(u8 nodeId) +{ + return (u8) (nodeId+PCI_DEV_BASE); +} diff --git a/src/northbridge/amd/amdht/AsPsNb.h b/src/northbridge/amd/amdht/AsPsNb.h new file mode 100644 index 0000000000..c7ac180b3e --- /dev/null +++ b/src/northbridge/amd/amdht/AsPsNb.h @@ -0,0 +1,26 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + + +#ifndef ASPSNB_H +#define ASPSNB_H + +u8 getMinNbCOF(void); + +#endif diff --git a/src/northbridge/amd/amdht/comlib.c b/src/northbridge/amd/amdht/comlib.c new file mode 100644 index 0000000000..47c538b19e --- /dev/null +++ b/src/northbridge/amd/amdht/comlib.c @@ -0,0 +1,290 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + +#undef FILECODE +#define FILECODE 0xCCCC +#include "comlib.h" + +/* + *--------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *--------------------------------------------------------------------------- + */ + +void CALLCONV AmdPCIReadBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue) +{ + ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0); + + AmdPCIRead(loc, pValue); + *pValue = *pValue >> lowbit; /* Shift */ + + /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */ + if ((highbit-lowbit) != 31) + *pValue &= (((u32)1 << (highbit-lowbit+1))-1); +} + + +void CALLCONV AmdPCIWriteBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue) +{ + u32 temp, mask; + + ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0); + + /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */ + if ((highbit-lowbit) != 31) + mask = (((u32)1 << (highbit-lowbit+1))-1); + else + mask = (u32)0xFFFFFFFF; + + AmdPCIRead(loc, &temp); + temp &= ~(mask << lowbit); + temp |= (*pValue & mask) << lowbit; + AmdPCIWrite(loc, &temp); +} + + +/* + * Given a SBDFO this routine will find the next PCI capabilities list entry. + * If the end of the list of reached, or if a problem is detected, then + * ILLEGAL_SBDFO is returned. + * + * To start a new search from the beginning of head of the list, specify a + * SBDFO with a offset of zero. + */ +void CALLCONV AmdPCIFindNextCap(SBDFO *pCurrent) +{ + SBDFO base; + u32 offset; + u32 temp; + + if (*pCurrent == ILLEGAL_SBDFO) + return; + + offset = SBDFO_OFF(*pCurrent); + base = *pCurrent - offset; + *pCurrent = ILLEGAL_SBDFO; + + /* Verify that the SBDFO points to a valid PCI device SANITY CHECK */ + AmdPCIRead(base, &temp); + if (temp == 0xFFFFFFFF) + return; /* There is no device at this address */ + + /* Verify that the device supports a capability list */ + AmdPCIReadBits(base + 0x04, 20, 20, &temp); + if (temp == 0) + return; /* This PCI device does not support capability lists */ + + if (offset != 0) + { + /* If we are continuing on an existing list */ + AmdPCIReadBits(base + offset, 15, 8, &temp); + } + else + { + /* We are starting on a new list */ + AmdPCIReadBits(base + 0x34, 7, 0, &temp); + } + + if (temp == 0) + return; /* We have reached the end of the capabilties list */ + + /* Error detection and recovery- The statement below protects against + PCI devices with broken PCI capabilities lists. Detect a pointer + that is not u32 aligned, points into the first 64 reserved DWORDs + or points back to itself. + */ + if (((temp & 3) != 0) || (temp == offset) || (temp < 0x40)) + return; + + *pCurrent = base + temp; + return; +} + + +void CALLCONV Amdmemcpy(void *pDst, const void *pSrc, u32 length) +{ + ASSERT(length <= 32768); + ASSERT(pDst != NULL); + ASSERT(pSrc != NULL); + + while (length--){ + // *(((u8*)pDst)++) = *(((u8*)pSrc)++); + *((u8*)pDst) = *((u8*)pSrc); + pDst++; + pSrc++; + } +} + + +void CALLCONV Amdmemset(void *pBuf, u8 val, u32 length) +{ + ASSERT(length <= 32768); + ASSERT(pBuf != NULL); + + while (length--){ + //*(((u8*)pBuf)++) = val; + *(((u8*)pBuf)) = val; + pBuf++; + } +} + + +u8 CALLCONV AmdBitScanReverse(u32 value) +{ + u8 i; + + for (i = 31; i != 0xFF; i--) + { + if (value & ((u32)1 << i)) + break; + } + + return i; +} + + +u32 CALLCONV AmdRotateRight(u32 value, u8 size, u32 count) +{ + u32 msb, mask; + ASSERT(size > 0 && size <= 32); + + msb = (u32)1 << (size-1); + mask = ((msb-1) << 1) + 1; + + value = value & mask; + + while (count--) + { + if (value & 1) + value = (value >> 1) | msb; + else + value = value >> 1; + } + + return value; +} + + +u32 CALLCONV AmdRotateLeft(u32 value, u8 size, u32 count) +{ + u32 msb, mask; + ASSERT(size > 0 && size <= 32); + + msb = (u32)1 << (size-1); + mask = ((msb-1) << 1) + 1; + + value = value & mask; + + while (count--) + { + if (value & msb) + value = ((value << 1) & mask) | (u32)1; + else + value = ((value << 1) & mask); + } + + return value; +} + + +void CALLCONV AmdPCIRead(SBDFO loc, u32 *Value) +{ + /* Use LinuxBIOS PCI functions */ + *Value = pci_read_config32((loc & 0xFFFFF000), SBDFO_OFF(loc)); +} + + +void CALLCONV AmdPCIWrite(SBDFO loc, u32 *Value) +{ + /* Use LinuxBIOS PCI functions */ + pci_write_config32((loc & 0xFFFFF000), SBDFO_OFF(loc), *Value); +} + + +void CALLCONV AmdMSRRead(uint32 Address, uint64 *Value) +{ + msr_t msr; + + msr = rdmsr(Address); + Value->lo = msr.lo; + Value->hi = msr.hi; +} + + +void CALLCONV AmdMSRWrite(uint32 Address, uint64 *Value) +{ + msr_t msr; + + msr.lo = Value->lo; + msr.hi = Value->hi; + wrmsr(Address, msr); +} + + +void ErrorStop(u32 value) +{ + printk_debug("Error: %08x ", value); + +} + +/*;---------------------------------------------------------------------------- +; void __pascal ErrorStop(DWORD Value); +; +; This implementation provides a rotating display of the error code on the +; a port 80h POST display card. The rotation is used to make it easier to +; view the error on both a 16-bit as well as a 32-bit display card. +; +; For use with SimNow the unrotated error code is also written to port 84h +ErrorStop PROC FAR PASCAL PUBLIC Value:DWORD + pushad + mov eax, Value + mov bx, 0DEADh + out 84h, eax + +ErrorStopTop: + out 80h, eax + + mov cx, 4 ; Rotate the display by one nibble +@@: + bt bx, 15 + rcl eax, 1 + rcl bx, 1 + loop @B + + + push eax ; Delay a few hundred milliseconds + push ebx + mov ecx, 10h ; TSC + db 00Fh, 032h ; RDMSR + mov ebx, eax +@@: + db 00Fh, 032h ; RDMSR + sub eax, ebx + cmp eax, 500000000 + jb @B + pop ebx + pop eax + + jmp ErrorStopTop + + popad + ret +ErrorStop ENDP +*/ diff --git a/src/northbridge/amd/amdht/comlib.h b/src/northbridge/amd/amdht/comlib.h new file mode 100644 index 0000000000..08c6d111f1 --- /dev/null +++ b/src/northbridge/amd/amdht/comlib.h @@ -0,0 +1,59 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + +#ifndef COMLIB_H +#define COMLIB_H + +#ifndef FILECODE +#error "FILECODE was not defined, should be #define'd to 0xFxxx" +#endif + +#include "porting.h" + +/* include LinuxBIOS pci functions */ +#include <device/pci_def.h> +#include <device/pci_ids.h> + +#ifdef AMD_DEBUG + #define ASSERT(x) ((x) ? 0 : ErrorStop(((uint32)FILECODE)*0x10000 + ((__LINE__)%10) + (((__LINE__/10)%10)*0x10) + (((__LINE__/100)%10)*0x100) +(((__LINE__/1000)%10)*0x1000))) +#else + #define ASSERT(x) +#endif + +#ifdef AMD_DEBUG_ERROR_STOP + /* Macro to aid debugging, causes program to halt and display the line number of the halt in decimal */ + #define STOP_HERE ErrorStop(((uint32)FILECODE)*0x10000 + ((__LINE__)%10) + (((__LINE__/10)%10)*0x10) + (((__LINE__/100)%10)*0x100) +(((__LINE__/1000)%10)*0x1000)) +#else + /* Macro to aid debugging, causes program to halt and display the line number of the halt in decimal */ + /* #define STOP_HERE STOP_HERE_OnlyForDebugUse */ + #define STOP_HERE +#endif + +void CALLCONV AmdPCIReadBits(SBDFO loc, uint8 highbit, uint8 lowbit, uint32 *value); +void CALLCONV AmdPCIWriteBits(SBDFO loc, uint8 highbit, uint8 lowbit, uint32 *value); +void CALLCONV AmdPCIFindNextCap(SBDFO *current); + +void CALLCONV Amdmemcpy(void *dst, const void *src, uint32 length); +void CALLCONV Amdmemset(void *buf, uint8 val, uint32 length); + +uint8 CALLCONV AmdBitScanReverse(uint32 value); +uint32 CALLCONV AmdRotateRight(uint32 value, uint8 size, uint32 count); +uint32 CALLCONV AmdRotateLeft(uint32 value, uint8 size, uint32 count); + +#endif diff --git a/src/northbridge/amd/amdht/h3ffeat.h b/src/northbridge/amd/amdht/h3ffeat.h new file mode 100644 index 0000000000..d415fee108 --- /dev/null +++ b/src/northbridge/amd/amdht/h3ffeat.h @@ -0,0 +1,177 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + + +#ifndef H3FFEAT_H +#define H3FFEAT_H + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +#define MAX_NODES 8 +#define MAX_LINKS 8 +#define MAX_PLATFORM_LINKS 64 /* 8x8 fully connected (28) + 4 chains with two HT devices */ + +/* These following are internal definitions */ +#define ROUTETOSELF 0x0F +#define INVALID_LINK 0xCC /* Used in port list data structure to mark unused data entries. + Can also be used for no link found in a port list search */ + +/* definitions for working with the port list structure */ +#define PORTLIST_TYPE_CPU 0 +#define PORTLIST_TYPE_IO 1 + +/* + * Hypertransport Capability definitions and macros + * + */ + +/* HT Host Capability */ +/* bool isHTHostCapability(u32 reg) */ +#define IS_HT_HOST_CAPABILITY(reg) \ + ((reg & (u32)0xE00000FF) == (u32)0x20000008) + +#define HT_HOST_CAP_SIZE 0x20 + +/* Host CapabilityRegisters */ +#define HTHOST_LINK_CAPABILITY_REG 0x00 +#define HTHOST_LINK_CONTROL_REG 0x04 +#define HTHOST_FREQ_REV_REG 0x08 + #define HT_HOST_REV_REV3 0x60 +#define HTHOST_FEATURE_CAP_REG 0x0C +#define HTHOST_BUFFER_COUNT_REG 0x10 +#define HTHOST_ISOC_REG 0x14 +#define HTHOST_LINK_TYPE_REG 0x18 + #define HTHOST_TYPE_COHERENT 3 + #define HTHOST_TYPE_NONCOHERENT 7 + #define HTHOST_TYPE_MASK 0x1F + +/* HT Slave Capability (HT1 compat) */ +#define IS_HT_SLAVE_CAPABILITY(reg) \ + ((reg & (u32)0xE00000FF) == (u32)0x00000008) +#define HTSLAVE_LINK01_OFFSET 4 +#define HTSLAVE_LINK_CONTROL_0_REG 4 +#define HTSLAVE_FREQ_REV_0_REG 0xC + +/* HT3 gen Capability */ +#define IS_HT_GEN3_CAPABILITY(reg) \ + ((reg & (u32)0xF80000FF) == (u32)0xD0000008) +#define HTGEN3_LINK01_OFFSET 0x10 +#define HTGEN3_LINK_TRAINING_0_REG 0x10 + +/* HT3 Retry Capability */ +#define IS_HT_RETRY_CAPABILITY(reg) \ + ((reg & (u32)0xF80000FF) == (u32)0xC0000008) + +#define HTRETRY_CONTROL_REG 4 + +/* Unit ID Clumping Capability */ +#define IS_HT_UNITID_CAPABILITY(reg) \ + ((reg & (u32)0xF80000FF) == (u32)0x90000008) + +#define HTUNIT_SUPPORT_REG 4 +#define HTUNIT_ENABLE_REG 8 + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +typedef struct cNorthBridge cNorthBridge; + +/* A pair consists of a source node, a link to the destination node, the + * destination node, and its link back to source node. The even indices are + * the source nodes and links, and the odd indices are for the destination + * nodes and links. + */ +typedef struct +{ + /* This section is where the link is in the system and how to find it */ + u8 Type; /* 0 = CPU, 1 = Device, all others reserved */ + u8 Link; /* 0-1 for devices, 0-7 for CPUs */ + u8 NodeID; /* The node, or a pointer to the devices parent node */ + u8 HostLink, HostDepth; /* Link of parent node + depth in chain. Only used by devices */ + SBDFO Pointer; /* A pointer to the device's slave HT capability, so we don't have to keep searching */ + + /* This section is for the final settings, which are written to hardware */ + BOOL SelRegang; /* Only used for CPU->CPU links */ + u8 SelWidthIn; + u8 SelWidthOut; + u8 SelFrequency; + + /* This section is for keeping track of capabilities and possible configurations */ + BOOL RegangCap; + u16 PrvFrequencyCap; + u8 PrvWidthInCap; + u8 PrvWidthOutCap; + u16 CompositeFrequencyCap; + +} sPortDescriptor; + + +/* + * Our global state data structure + */ +typedef struct { + AMD_HTBLOCK *HtBlock; + + u8 NodesDiscovered; /* One less than the number of nodes found in the system */ + u8 TotalLinks; + u8 sysMpCap; /* The maximum number of nodes that all processors are capable of */ + + /* Two ports for each link + * Note: The Port pair 2*N and 2*N+1 are connected together to form a link + * (e.g. 0,1 and 8,9 are ports on either end of an HT link) The lower number + * port (2*N) is the source port. The device that owns the source port is + * always the device closer to the BSP. (i.e. nearer the CPU in a + * non-coherent chain, or the CPU with the lower NodeID). + */ + sPortDescriptor PortList[MAX_PLATFORM_LINKS*2]; + + /* The number of coherent links comming off of each node (i.e. the 'Degree' of the node) */ + u8 sysDegree[MAX_NODES]; + /* The systems adjency (sysMatrix[i][j] is true if Node_i has a link to Node_j) */ + BOOL sysMatrix[MAX_NODES][MAX_NODES]; + + /* Same as above, but for the currently selected database entry */ + u8 dbDegree[MAX_NODES]; + BOOL dbMatrix[MAX_NODES][MAX_NODES]; + + u8 Perm[MAX_NODES]; /* The node mapping from the database to the system */ + u8 ReversePerm[MAX_NODES]; /* The node mapping from the system to the database */ + + /* Data for non-coherent initilization */ + u8 AutoBusCurrent; + u8 UsedCfgMapEntires; + + /* 'This' pointer for northbridge */ + cNorthBridge *nb; +} sMainData; + +#endif /* H3FFEAT_H */ diff --git a/src/northbridge/amd/amdht/h3finit.c b/src/northbridge/amd/amdht/h3finit.c new file mode 100644 index 0000000000..dd3e3813bd --- /dev/null +++ b/src/northbridge/amd/amdht/h3finit.c @@ -0,0 +1,1678 @@ +/* + * This file is part of the LinuxBIOS 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 0xF001 + +#include "comlib.h" +#include "h3finit.h" +#include "h3ffeat.h" +#include "h3ncmn.h" +#include "h3gtopo.h" +#include "AsPsNb.h" +/* this is pre-ram so include the required C files here */ +#include "comlib.c" +#include "AsPsNb.c" +#include "h3ncmn.c" + +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +#undef FILECODE +#define FILECODE 0xF001 + +/* APIC defines from amdgesa.inc, which can't be included in to c code. */ +#define APIC_Base_BSP 8 +#define APIC_Base 0x1b + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ +#ifndef HT_BUILD_NC_ONLY +/* + ************************************************************************** + * Routing table decompressor + ************************************************************************** + */ + +/* + ************************************************************************** + * Graph Support routines + * These routines provide support for dealing with the graph representation + * of the topologies, along with the routing table information for that topology. + * The routing information is compressed and these routines currently decompress + * 'on the fly'. A graph is represented as a set of routes. All the edges in the + * graph are routes; a direct route from node i to node j exists in the graph IFF + * there is an edge directly connecting node i to node j. All other routes designate + * the edge which the route to that node initially takes, by designating a node + * to which a direct connection exists. That is, the route to non-adjacent node j + * from node i specifies node k where node i directly connects to node k. + * + * + * pseudo definition of compressed graph: + * typedef struct + * { + * BIT broadcast[8]; + * uint4 responseRoute; + * uint4 requestRoute; + * } sRoute; + * typedef struct + * { + * u8 size; + * sRoute graph[size][size]; + * } sGraph; + * + ************************************************************************** + */ + +/*---------------------------------------------------------------------------------------- + * int + * graphHowManyNodes(u8 *graph) + * + * Description: + * Returns the number of nodes in the compressed graph + * + * Parameters: + * @param[in] u8 graph = a compressed graph + * @param[out] u8 results = the number of nodes in the graph + * --------------------------------------------------------------------------------------- + */ +int graphHowManyNodes(u8 *graph) +{ + return graph[0]; +} + +/*---------------------------------------------------------------------------------------- + * BOOL + * graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB) + * + * Description: + * Returns true if NodeA is directly connected to NodeB, false otherwise + * (if NodeA == NodeB also returns false) + * Relies on rule that directly connected nodes always route requests directly. + * + * Parameters: + * @param[in] u8 graph = the graph to examine + * @param[in] u8 nodeA = the node number of the first node + * @param[in] u8 nodeB = the node number of the second node + * @param[out] BOOL results = true if nodeA connects to nodeB false if not + * --------------------------------------------------------------------------------------- + */ +BOOL graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB) +{ + u8 size = graph[0]; + ASSERT(size <= MAX_NODES); + ASSERT((nodeA < size) && (nodeB < size)); + return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F) == nodeB; +} + +/*---------------------------------------------------------------------------------------- + * u8 + * graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB) + * + * Description: + * Returns the graph node used by nodeA to route responses targeted at nodeB. + * This will be a node directly connected to nodeA (possibly nodeB itself), + * or "Route to Self" if nodeA and nodeB are the same node. + * Note that all node numbers are abstract node numbers of the topology graph, + * it is the responsibility of the caller to apply any permutation needed. + * + * Parameters: + * @param[in] u8 graph = the graph to examine + * @param[in] u8 nodeA = the node number of the first node + * @param[in] u8 nodeB = the node number of the second node + * @param[out] u8 results = The response route node + * --------------------------------------------------------------------------------------- + */ +u8 graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB) +{ + u8 size = graph[0]; + ASSERT(size <= MAX_NODES); + ASSERT((nodeA < size) && (nodeB < size)); + return (graph[1+(nodeA*size+nodeB)*2+1] & 0xF0)>>4; +} + +/*---------------------------------------------------------------------------------------- + * u8 + * graphGetReq(u8 *graph, u8 nodeA, u8 nodeB) + * + * Description: + * Returns the graph node used by nodeA to route requests targeted at nodeB. + * This will be a node directly connected to nodeA (possibly nodeB itself), + * or "Route to Self" if nodeA and nodeB are the same node. + * Note that all node numbers are abstract node numbers of the topology graph, + * it is the responsibility of the caller to apply any permutation needed. + * + * Parameters: + * @param[in] u8 graph = the graph to examine + * @param[in] u8 nodeA = the node number of the first node + * @param[in] u8 nodeB = the node number of the second node + * @param[out] u8 results = The request route node + * --------------------------------------------------------------------------------------- + */ +u8 graphGetReq(u8 *graph, u8 nodeA, u8 nodeB) +{ + int size = graph[0]; + ASSERT(size <= MAX_NODES); + ASSERT((nodeA < size) && (nodeB < size)); + return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F); +} + +/*---------------------------------------------------------------------------------------- + * u8 + * graphGetBc(unsigned char *graph, int nodeA, int nodeB) + * + * Description: + * Returns a bit vector of nodes that nodeA should forward a broadcast from + * nodeB towards + * + * Parameters: + * @param[in] u8 graph = the graph to examine + * @param[in] u8 nodeA = the node number of the first node + * @param[in] u8 nodeB = the node number of the second node + * OU u8 results = the broadcast routes for nodeA from nodeB + * --------------------------------------------------------------------------------------- + */ +u8 graphGetBc(unsigned char *graph, int nodeA, int nodeB) +{ + int size = graph[0]; + ASSERT(size <= MAX_NODES); + ASSERT((nodeA < size) && (nodeB < size)); + return graph[1+(nodeA*size+nodeB)*2]; +} + + +/*************************************************************************** + *** GENERIC HYPERTRANSPORT DISCOVERY CODE *** + ***************************************************************************/ + +/*---------------------------------------------------------------------------------------- + * void + * routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat) + * + * Description: + * Ensure a request / response route from target node to bsp. Since target node is + * always a predecessor of actual target node, each node gets a route to actual target + * on the link that goes to target. The routing produced by this routine is adequate + * for config access during discovery, but NOT for coherency. + * + * Parameters: + * @param[in] u8 targetNode = the path to actual target goes through target + * @param[in] u8 actualTarget = the ultimate target being routed to + * @param[in] sMainData* pDat = our global state, port config info + * --------------------------------------------------------------------------------------- + */ +void routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat) +{ + u8 predecessorNode, predecessorLink, currentPair; + + if (targetNode == 0) + return; // BSP has no predecessor, stop + + // Search for the link that connects targetNode to its predecessor + currentPair = 0; + while (pDat->PortList[currentPair*2+1].NodeID != targetNode) + { + currentPair++; + ASSERT(currentPair < pDat->TotalLinks); + } + + predecessorNode = pDat->PortList[currentPair*2].NodeID; + predecessorLink = pDat->PortList[currentPair*2].Link; + + // Recursively call self to ensure the route from the BSP to the Predecessor + // Node is established + routeFromBSP(predecessorNode, actualTarget, pDat); + + pDat->nb->writeRoutingTable(predecessorNode, actualTarget, predecessorLink, pDat->nb); +} + +/*---------------------------------------------------------------------------------------- + * u8 + * convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat) + * + * Description: + * Return the link on source node which connects to target node + * + * Parameters: + * @param[in] u8 srcNode = the source node + * @param[in] u8 targetNode = the target node to find the link to + * @param[in] sMainData* pDat = our global state + * @param[out] u8 results = the link on source which connects to target + * --------------------------------------------------------------------------------------- + */ +u8 convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat) +{ + u8 targetlink = INVALID_LINK; + u8 k; + + for (k = 0; k < pDat->TotalLinks*2; k += 2) + { + if ((pDat->PortList[k+0].NodeID == srcNode) && (pDat->PortList[k+1].NodeID == targetNode)) + { + targetlink = pDat->PortList[k+0].Link; + break; + } + else if ((pDat->PortList[k+1].NodeID == srcNode) && (pDat->PortList[k+0].NodeID == targetNode)) + { + targetlink = pDat->PortList[k+1].Link; + break; + } + } + ASSERT(targetlink != INVALID_LINK); + + return targetlink; +} + + +/*---------------------------------------------------------------------------------------- + * void + * htDiscoveryFloodFill(sMainData *pDat) + * + * Description: + * Discover all coherent devices in the system, initializing some basics like node IDs + * and total nodes found in the process. As we go we also build a representation of the + * discovered system which we will use later to program the routing tables. During this + * step, the routing is via default link back to BSP and to each new node on the link it + * was discovered on (no coherency is active yet). + * + * Parameters: + * @param[in] sMainData* pDat = our global state + * --------------------------------------------------------------------------------------- + */ +void htDiscoveryFloodFill(sMainData *pDat) +{ + u8 currentNode = 0; + u8 currentLink; + + /* Entries are always added in pairs, the even indices are the 'source' + * side closest to the BSP, the odd indices are the 'destination' side + */ + + while (currentNode <= pDat->NodesDiscovered) + { + u32 temp; + + if (currentNode != 0) + { + /* Set path from BSP to currentNode */ + routeFromBSP(currentNode, currentNode, pDat); + + /* Set path from BSP to currentNode for currentNode+1 if + * currentNode+1 != MAX_NODES + */ + if (currentNode+1 != MAX_NODES) + routeFromBSP(currentNode, currentNode+1, pDat); + + /* Configure currentNode to route traffic to the BSP through its + * default link + */ + pDat->nb->writeRoutingTable(currentNode, 0, pDat->nb->readDefLnk(currentNode, pDat->nb), pDat->nb); + } + + /* Set currentNode's NodeID field to currentNode */ + pDat->nb->writeNodeID(currentNode, currentNode, pDat->nb); + + /* Enable routing tables on currentNode*/ + pDat->nb->enableRoutingTables(currentNode, pDat->nb); + + for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++) + { + BOOL linkfound; + u8 token; + + if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(currentNode, currentLink)) + continue; + + if (pDat->nb->readTrueLinkFailStatus(currentNode, currentLink, pDat, pDat->nb)) + continue; + + /* Make sure that the link is connected, coherent, and ready */ + if (!pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb)) + continue; + + + /* Test to see if the currentLink has already been explored */ + linkfound = FALSE; + for (temp = 0; temp < pDat->TotalLinks; temp++) + { + if ((pDat->PortList[temp*2+1].NodeID == currentNode) && + (pDat->PortList[temp*2+1].Link == currentLink)) + { + linkfound = TRUE; + break; + } + } + if (linkfound) + { + /* We had already expored this link */ + continue; + } + + if (pDat->nb->handleSpecialLinkCase(currentNode, currentLink, pDat, pDat->nb)) + { + continue; + } + + /* Modify currentNode's routing table to use currentLink to send + * traffic to currentNode+1 + */ + pDat->nb->writeRoutingTable(currentNode, currentNode+1, currentLink, pDat->nb); + + /* Check the northbridge of the node we just found, to make sure it is compatible + * before doing anything else to it. + */ + if (!pDat->nb->isCompatible(currentNode+1, pDat->nb)) + { + u8 nodeToKill; + + /* Notify BIOS of event (while variables are still the same) */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventCohFamilyFeud evt = {sizeof(sHtEventCohFamilyFeud), + currentNode, + currentLink, + pDat->NodesDiscovered}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, + HT_EVENT_COH_FAMILY_FEUD, + (u8 *)&evt); + } + + /* If node is not compatible, force boot to 1P + * If they are not compatible stop cHT init and: + * 1. Disable all cHT links on the BSP + * 2. Configure the BSP routing tables as a UP. + * 3. Notify main BIOS. + */ + pDat->NodesDiscovered = 0; + currentNode = 0; + pDat->TotalLinks = 0; + /* Abandon our coherent link data structure. At this point there may + * be coherent links on the BSP that are not yet in the portList, and + * we have to turn them off anyway. So depend on the hardware to tell us. + */ + for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++) + { + /* Stop all links which are connected, coherent, and ready */ + if (pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb)) + pDat->nb->stopLink(currentNode, currentLink, pDat->nb); + } + + for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++) + { + pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb); + } + + /* End Coherent Discovery */ + STOP_HERE; + break; + } + + /* Read token from Current+1 */ + token = pDat->nb->readToken(currentNode+1, pDat->nb); + ASSERT(token <= pDat->NodesDiscovered); + if (token == 0) + { + pDat->NodesDiscovered++; + ASSERT(pDat->NodesDiscovered < pDat->nb->maxNodes); + /* Check the capability of northbridges against the currently known configuration */ + if (!pDat->nb->isCapable(currentNode+1, pDat, pDat->nb)) + { + u8 nodeToKill; + + /* Notify BIOS of event */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventCohMpCapMismatch evt = {sizeof(sHtEventCohMpCapMismatch), + currentNode, + currentLink, + pDat->sysMpCap, + pDat->NodesDiscovered}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, + HT_EVENT_COH_MPCAP_MISMATCH, + (u8 *)&evt); + } + + pDat->NodesDiscovered = 0; + currentNode = 0; + pDat->TotalLinks = 0; + + for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++) + { + pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb); + } + + /* End Coherent Discovery */ + STOP_HERE; + break; + } + + token = pDat->NodesDiscovered; + pDat->nb->writeToken(currentNode+1, token, pDat->nb); + /* Inform that we have discovered a node, so that logical id to + * socket mapping info can be recorded. + */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventCohNodeDiscovered evt = {sizeof(sHtEventCohNodeDiscovered), + currentNode, + currentLink, + token}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO, + HT_EVENT_COH_NODE_DISCOVERED, + (u8 *)&evt); + } + } + + if (pDat->TotalLinks == MAX_PLATFORM_LINKS) + { + /* + * Exceeded our capacity to describe all coherent links found in the system. + * Error strategy: + * Auto recovery is not possible because data space is already all used. + * If the callback is not implemented or returns we will continue to initialize + * the fabric we are capable of representing, adding no more nodes or links. + * This should yield a bootable topology, but likely not the one intended. + * We cannot continue discovery, there may not be any way to route a new + * node back to the BSP if we can't add links to our representation of the system. + */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventCohLinkExceed evt = {sizeof(sHtEventCohLinkExceed), + currentNode, + currentLink, + token, + pDat->NodesDiscovered, + pDat->nb->maxLinks}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, + HT_EVENT_COH_LINK_EXCEED, + (u8 *)&evt); + } + /* Force link and node loops to halt */ + STOP_HERE; + currentNode = pDat->NodesDiscovered; + break; + } + + pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU; + pDat->PortList[pDat->TotalLinks*2].Link = currentLink; + pDat->PortList[pDat->TotalLinks*2].NodeID = currentNode; + + pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_CPU; + pDat->PortList[pDat->TotalLinks*2+1].Link = pDat->nb->readDefLnk(currentNode+1, pDat->nb); + pDat->PortList[pDat->TotalLinks*2+1].NodeID = token; + + pDat->TotalLinks++; + + if ( !pDat->sysMatrix[currentNode][token] ) + { + pDat->sysDegree[currentNode]++; + pDat->sysDegree[token]++; + pDat->sysMatrix[currentNode][token] = TRUE; + pDat->sysMatrix[token][currentNode] = TRUE; + } + } + currentNode++; + } +} + + +/*************************************************************************** + *** ISOMORPHISM BASED ROUTING TABLE GENERATION CODE *** + ***************************************************************************/ + +/*---------------------------------------------------------------------------------------- + * BOOL + * isoMorph(u8 i, sMainData *pDat) + * + * Description: + * Is graphA isomorphic to graphB? + * if this function returns true, then Perm will contain the permutation + * required to transform graphB into graphA. + * We also use the degree of each node, that is the number of connections it has, to + * speed up rejection of non-isomorphic graphs (if there is a node in graphA with n + * connections, there must be at least one unmatched in graphB with n connections). + * + * Parameters: + * @param[in] u8 i = the discovered node which we are trying to match + * with a permutation the topology + * @param[in]/@param[out] sMainData* pDat = our global state, degree and adjacency matrix, + * output a permutation if successful + * @param[out] BOOL results = the graphs are (or are not) isomorphic + * --------------------------------------------------------------------------------------- + */ +BOOL isoMorph(u8 i, sMainData *pDat) +{ + u8 j, k; + u8 nodecnt; + + /* We have only been called if nodecnt == pSelected->size ! */ + nodecnt = pDat->NodesDiscovered+1; + + if (i != nodecnt) + { + // Keep building the permutation + for (j = 0; j < nodecnt; j++) + { + // Make sure the degree matches + if (pDat->sysDegree[i] != pDat->dbDegree[j]) + continue; + + // Make sure that j hasn't been used yet (ought to use a "used" + // array instead, might be faster) + for (k = 0; k < i; k++) + { + if (pDat->Perm[k] == j) + break; + } + if (k != i) + continue; + pDat->Perm[i] = j; + if (isoMorph(i+1, pDat)) + return TRUE; + } + return FALSE; + } else { + // Test to see if the permutation is isomorphic + for (j = 0; j < nodecnt; j++) + { + for (k = 0; k < nodecnt; k++) + { + if ( pDat->sysMatrix[j][k] != + pDat->dbMatrix[pDat->Perm[j]][pDat->Perm[k]] ) + return FALSE; + } + } + return TRUE; + } +} + + +/*---------------------------------------------------------------------------------------- + * void + * lookupComputeAndLoadRoutingTables(sMainData *pDat) + * + * Description: + * Using the description of the fabric topology we discovered, try to find a match + * among the supported topologies. A supported topology description matches + * the discovered fabric if the nodes can be matched in such a way that all the nodes connected + * in one set are exactly the nodes connected in the other (formally, that the graphs are + * isomorphic). Which links are used is not really important to matching. If the graphs + * match, then there is a permutation of one that translates the node positions and linkages + * to the other. + * + * In order to make the isomorphism test efficient, we test for matched number of nodes + * (a 4 node fabric is not isomorphic to a 2 node topology), and provide degrees of nodes + * to the isomorphism test. + * + * The generic routing table solution for any topology is predetermined and represented + * as part of the topology. The permutation we computed tells us how to interpret the + * routing onto the fabric we discovered. We do this working backward from the last + * node discovered to the BSP, writing the routing tables as we go. + * + * Parameters: + * @param[in] sMainData* pDat = our global state, the discovered fabric, + * @param[out] degree matrix, permutation + * --------------------------------------------------------------------------------------- + */ +void lookupComputeAndLoadRoutingTables(sMainData *pDat) +{ + u8 **pTopologyList; + u8 *pSelected; + + int i, j, k, size; + + size = pDat->NodesDiscovered + 1; + /* Use the provided topology list or the internal, default one. */ + pTopologyList = pDat->HtBlock->topolist; + if (pTopologyList == NULL) + { + getAmdTopolist(&pTopologyList); + } + + pSelected = *pTopologyList; + while (pSelected != NULL) + { + if (graphHowManyNodes(pSelected) == size) + { + // Build Degree vector and Adjency Matrix for this entry + for (i = 0; i < size; i++) + { + pDat->dbDegree[i] = 0; + for (j = 0; j < size; j++) + { + if (graphIsAdjacent(pSelected, i, j)) + { + pDat->dbMatrix[i][j] = 1; + pDat->dbDegree[i]++; + } + else + { + pDat->dbMatrix[i][j] = 0; + } + } + } + if (isoMorph(0, pDat)) + break; // A matching topology was found + } + + pTopologyList++; + pSelected = *pTopologyList; + } + + if (pSelected != NULL) + { + // Compute the reverse Permutation + for (i = 0; i < size; i++) + { + pDat->ReversePerm[pDat->Perm[i]] = i; + } + + // Start with the last discovered node, and move towards the BSP + for (i = size-1; i >= 0; i--) + { + for (j = 0; j < size; j++) + { + u8 ReqTargetLink, RspTargetLink; + u8 ReqTargetNode, RspTargetNode; + + u8 AbstractBcTargetNodes = graphGetBc(pSelected, pDat->Perm[i], pDat->Perm[j]); + u32 BcTargetLinks = 0; + + for (k = 0; k < MAX_NODES; k++) + { + if (AbstractBcTargetNodes & ((u32)1<<k)) + { + BcTargetLinks |= (u32)1 << convertNodeToLink(i, pDat->ReversePerm[k], pDat); + } + } + + if (i == j) + { + ReqTargetLink = ROUTETOSELF; + RspTargetLink = ROUTETOSELF; + } + else + { + ReqTargetNode = graphGetReq(pSelected, pDat->Perm[i], pDat->Perm[j]); + ReqTargetLink = convertNodeToLink(i, pDat->ReversePerm[ReqTargetNode], pDat); + + RspTargetNode = graphGetRsp(pSelected, pDat->Perm[i], pDat->Perm[j]); + RspTargetLink = convertNodeToLink(i, pDat->ReversePerm[RspTargetNode], pDat); + } + + pDat->nb->writeFullRoutingTable(i, j, ReqTargetLink, RspTargetLink, BcTargetLinks, pDat->nb); + } + /* Clean up discovery 'footprint' that otherwise remains in the routing table. It didn't hurt + * anything, but might cause confusion during debug and validation. Do this by setting the + * route back to all self routes. Since it's the node that would be one more than actually installed, + * this only applies if less than maxNodes were found. + */ + if (size < pDat->nb->maxNodes) + { + pDat->nb->writeFullRoutingTable(i, size, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb); + } + } + + } + else + { + /* + * No Matching Topology was found + * Error Strategy: + * Auto recovery doesn't seem likely, Force boot as 1P. + * For reporting, logging, provide number of nodes + * If not implemented or returns, boot as BSP uniprocessor. + */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventCohNoTopology evt = {sizeof(sHtEventCohNoTopology), + pDat->NodesDiscovered}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, + HT_EVENT_COH_NO_TOPOLOGY, + (u8 *)&evt); + } + STOP_HERE; + /* Force 1P */ + pDat->NodesDiscovered = 0; + pDat->TotalLinks = 0; + pDat->nb->enableRoutingTables(0, pDat->nb); + } +} +#endif /* HT_BUILD_NC_ONLY */ + + +/*---------------------------------------------------------------------------------------- + * void + * finializeCoherentInit(sMainData *pDat) + * + * Description: + * Find the total number of cores and update the number of nodes and cores in all cpus. + * Limit cpu config access to installed cpus. + * + * Parameters: + * @param[in] sMainData* pDat = our global state, number of nodes discovered. + * --------------------------------------------------------------------------------------- + */ +void finializeCoherentInit(sMainData *pDat) +{ + u8 curNode; + + u8 totalCores = 0; + for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) + { + totalCores += pDat->nb->getNumCoresOnNode(curNode, pDat->nb); + } + + for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) + { + pDat->nb->setTotalNodesAndCores(curNode, pDat->NodesDiscovered+1, totalCores, pDat->nb); + } + + for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++) + { + pDat->nb->limitNodes(curNode, pDat->nb); + } + +} + +/*---------------------------------------------------------------------------------------- + * void + * coherentInit(sMainData *pDat) + * + * Description: + * Perform discovery and initialization of the coherent fabric. + * + * Parameters: + * @param[in] sMainData* pDat = our global state + * --------------------------------------------------------------------------------------- + */ +void coherentInit(sMainData *pDat) +{ + int i, j; + +#ifdef HT_BUILD_NC_ONLY + /* Replace discovery process with: + * No other nodes, no coherent links + * Enable routing tables on currentNode, for power on self route + */ + pDat->NodesDiscovered = 0; + pDat->TotalLinks = 0; + pDat->nb->enableRoutingTables(0, pDat->nb); +#else + pDat->NodesDiscovered = 0; + pDat->TotalLinks = 0; + for (i = 0; i < MAX_NODES; i++) + { + pDat->sysDegree[i] = 0; + for (j = 0; j < MAX_NODES; j++) + { + pDat->sysMatrix[i][j] = 0; + } + } + + htDiscoveryFloodFill(pDat); + lookupComputeAndLoadRoutingTables(pDat); +#endif + finializeCoherentInit(pDat); +} + +/*************************************************************************** + *** Non-coherent init code *** + *** Algorithms *** + ***************************************************************************/ +/*---------------------------------------------------------------------------------------- + * void + * processLink(u8 node, u8 link, sMainData *pDat) + * + * Description: + * Process a non-coherent link, enabling a range of bus numbers, and setting the device + * ID for all devices found + * + * Parameters: + * @param[in] u8 node = Node on which to process nc init + * @param[in] u8 link = The non-coherent link on that node + * @param[in] sMainData* pDat = our global state + * --------------------------------------------------------------------------------------- + */ +void processLink(u8 node, u8 link, sMainData *pDat) +{ + u8 secBus, subBus; + u32 currentBUID; + u32 temp; + u32 unitIDcnt; + SBDFO currentPtr; + u8 depth; + u8 *pSwapPtr; + + SBDFO lastSBDFO = ILLEGAL_SBDFO; + u8 lastLink = 0; + + ASSERT(node < pDat->nb->maxNodes && link < pDat->nb->maxLinks); + + if ((pDat->HtBlock->AMD_CB_OverrideBusNumbers == NULL) + || !pDat->HtBlock->AMD_CB_OverrideBusNumbers(node, link, &secBus, &subBus)) + { + /* Assign Bus numbers */ + if (pDat->AutoBusCurrent >= pDat->HtBlock->AutoBusMax) + { + /* If we run out of Bus Numbers notify, if call back unimplemented or if it + * returns, skip this chain + */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHTEventNcohBusMaxExceed evt = {sizeof(sHTEventNcohBusMaxExceed), node, link, pDat->AutoBusCurrent}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUS_MAX_EXCEED,(u8 *)&evt); + } + STOP_HERE; + return; + } + + if (pDat->UsedCfgMapEntires >= 4) + { + /* If we have used all the PCI Config maps we can't add another chain. + * Notify and if call back is unimplemented or returns, skip this chain. + */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventNcohCfgMapExceed evt = {sizeof(sHtEventNcohCfgMapExceed), node, link}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, + HT_EVENT_NCOH_CFG_MAP_EXCEED, + (u8 *)&evt); + } + STOP_HERE; + return; + } + + secBus = pDat->AutoBusCurrent; + subBus = secBus + pDat->HtBlock->AutoBusIncrement-1; + pDat->AutoBusCurrent += pDat->HtBlock->AutoBusIncrement; + } + + pDat->nb->setCFGAddrMap(pDat->UsedCfgMapEntires, secBus, subBus, node, link, pDat, pDat->nb); + pDat->UsedCfgMapEntires++; + + if ((pDat->HtBlock->AMD_CB_ManualBUIDSwapList != NULL) + && pDat->HtBlock->AMD_CB_ManualBUIDSwapList(node, link, &pSwapPtr)) + { + /* Manual non-coherent BUID assignment */ + + /* Assign BUID's per manual override */ + while (*pSwapPtr != 0xFF) + { + currentPtr = MAKE_SBDFO(0, secBus, *pSwapPtr, 0, 0); + pSwapPtr++; + + do + { + AmdPCIFindNextCap(¤tPtr); + ASSERT(currentPtr != ILLEGAL_SBDFO); + AmdPCIRead(currentPtr, &temp); + } while (!IS_HT_SLAVE_CAPABILITY(temp)); + + currentBUID = *pSwapPtr; + pSwapPtr++; + AmdPCIWriteBits(currentPtr, 20, 16, ¤tBUID); + } + + /* Build chain of devices */ + depth = 0; + pSwapPtr++; + while (*pSwapPtr != 0xFF) + { + pDat->PortList[pDat->TotalLinks*2].NodeID = node; + if (depth == 0) + { + pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU; + pDat->PortList[pDat->TotalLinks*2].Link = link; + } + else + { + pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO; + pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink; + pDat->PortList[pDat->TotalLinks*2].HostLink = link; + pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1; + pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO; + } + + pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO; + pDat->PortList[pDat->TotalLinks*2+1].NodeID = node; + pDat->PortList[pDat->TotalLinks*2+1].HostLink = link; + pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth; + + currentPtr = MAKE_SBDFO(0, secBus, (*pSwapPtr & 0x3F), 0, 0); + do + { + AmdPCIFindNextCap(¤tPtr); + ASSERT(currentPtr != ILLEGAL_SBDFO); + AmdPCIRead(currentPtr, &temp); + } while (!IS_HT_SLAVE_CAPABILITY(temp)); + pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr; + lastSBDFO = currentPtr; + + /* Bit 6 indicates whether orientation override is desired. + * Bit 7 indicates the upstream link if overriding. + */ + /* assert catches at least the one known incorrect setting */ + ASSERT ((*pSwapPtr & 0x40) || (!(*pSwapPtr & 0x80))); + if (*pSwapPtr & 0x40) + { + /* Override the device's orientation */ + lastLink = *pSwapPtr >> 7; + } + else + { + /* Detect the device's orientation */ + AmdPCIReadBits(currentPtr, 26, 26, &temp); + lastLink = (u8)temp; + } + pDat->PortList[pDat->TotalLinks*2+1].Link = lastLink; + + depth++; + pDat->TotalLinks++; + pSwapPtr++; + } + } + else + { + /* Automatic non-coherent device detection */ + depth = 0; + currentBUID = 1; + while (1) + { + currentPtr = MAKE_SBDFO(0, secBus, 0, 0, 0); + + AmdPCIRead(currentPtr, &temp); + if (temp == 0xFFFFFFFF) + /* No device found at currentPtr */ + break; + + if (pDat->TotalLinks == MAX_PLATFORM_LINKS) + { + /* + * Exceeded our capacity to describe all non-coherent links found in the system. + * Error strategy: + * Auto recovery is not possible because data space is already all used. + */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventNcohLinkExceed evt = {sizeof(sHtEventNcohLinkExceed), + node, + link, + depth, + pDat->nb->maxLinks}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR, + HT_EVENT_NCOH_LINK_EXCEED, + (u8 *)&evt); + } + /* Force link loop to halt */ + STOP_HERE; + break; + } + + pDat->PortList[pDat->TotalLinks*2].NodeID = node; + if (depth == 0) + { + pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU; + pDat->PortList[pDat->TotalLinks*2].Link = link; + } + else + { + pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO; + pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink; + pDat->PortList[pDat->TotalLinks*2].HostLink = link; + pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1; + pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO; + } + + pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO; + pDat->PortList[pDat->TotalLinks*2+1].NodeID = node; + pDat->PortList[pDat->TotalLinks*2+1].HostLink = link; + pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth; + + do + { + AmdPCIFindNextCap(¤tPtr); + ASSERT(currentPtr != ILLEGAL_SBDFO); + AmdPCIRead(currentPtr, &temp); + } while (!IS_HT_SLAVE_CAPABILITY(temp)); + + AmdPCIReadBits(currentPtr, 25, 21, &unitIDcnt); + if ((unitIDcnt + currentBUID > 31) || ((secBus == 0) && (unitIDcnt + currentBUID > 24))) + { + /* An error handler for the case where we run out of BUID's on a chain */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventNcohBuidExceed evt = {sizeof(sHtEventNcohBuidExceed), + node, link, depth, (u8)currentBUID, (u8)unitIDcnt}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUID_EXCEED,(u8 *)&evt); + } + STOP_HERE; + break; + } + AmdPCIWriteBits(currentPtr, 20, 16, ¤tBUID); + + + currentPtr += MAKE_SBDFO(0, 0, currentBUID, 0, 0); + AmdPCIReadBits(currentPtr, 20, 16, &temp); + if (temp != currentBUID) + { + /* An error handler for this critical error */ + if (pDat->HtBlock->AMD_CB_EventNotify) + { + sHtEventNcohDeviceFailed evt = {sizeof(sHtEventNcohDeviceFailed), + node, link, depth, (u8)currentBUID}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_DEVICE_FAILED,(u8 *)&evt); + } + STOP_HERE; + break; + } + + AmdPCIReadBits(currentPtr, 26, 26, &temp); + pDat->PortList[pDat->TotalLinks*2+1].Link = (u8)temp; + pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr; + + lastLink = (u8)temp; + lastSBDFO = currentPtr; + + depth++; + pDat->TotalLinks++; + currentBUID += unitIDcnt; + } + if (pDat->HtBlock->AMD_CB_EventNotify) + { + /* Provide information on automatic device results */ + sHtEventNcohAutoDepth evt = {sizeof(sHtEventNcohAutoDepth), node, link, (depth - 1)}; + + pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,HT_EVENT_NCOH_AUTO_DEPTH,(u8 *)&evt); + } + } +} + + +/*---------------------------------------------------------------------------------------- + * void + * ncInit(sMainData *pDat) + * + * Description: + * Initialize the non-coherent fabric. Begin with the compat link on the BSP, then + * find and initialize all other non-coherent chains. + * + * Parameters: + * @param[in] sMainData* pDat = our global state + * --------------------------------------------------------------------------------------- + */ +void ncInit(sMainData *pDat) +{ + u8 node, link; + u8 compatLink; + + compatLink = pDat->nb->readSbLink(pDat->nb); + processLink(0, compatLink, pDat); + + for (node = 0; node <= pDat->NodesDiscovered; node++) + { + for (link = 0; link < pDat->nb->maxLinks; link++) + { + if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(node, link)) + continue; // Skip the link + + if (node == 0 && link == compatLink) + continue; + + if (pDat->nb->readTrueLinkFailStatus(node, link, pDat, pDat->nb)) + continue; + + if (pDat->nb->verifyLinkIsNonCoherent(node, link, pDat->nb)) + processLink(node, link, pDat); + } + } +} + +/*************************************************************************** + *** Link Optimization *** + ***************************************************************************/ + +/*---------------------------------------------------------------------------------------- + * void + * regangLinks(sMainData *pDat) + * + * Description: + * Test the sublinks of a link to see if they qualify to be reganged. If they do, + * update the port list data to indicate that this should be done. Note that no + * actual hardware state is changed in this routine. + * + * Parameters: + * @param[in,out] sMainData* pDat = our global state + * --------------------------------------------------------------------------------------- + */ +void regangLinks(sMainData *pDat) +{ +#ifndef HT_BUILD_NC_ONLY + u8 i, j; + for (i = 0; i < pDat->TotalLinks*2; i += 2) + { + ASSERT(pDat->PortList[i].Type < 2 && pDat->PortList[i].Link < pDat->nb->maxLinks); // Data validation + ASSERT(pDat->PortList[i+1].Type < 2 && pDat->PortList[i+1].Link < pDat->nb->maxLinks); // data validation + ASSERT(!(pDat->PortList[i].Type == PORTLIST_TYPE_IO && pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU)); // ensure src is closer to the bsp than dst + + /* Regang is false unless we pass all conditions below */ + pDat->PortList[i].SelRegang = FALSE; + pDat->PortList[i+1].SelRegang = FALSE; + + if ( (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[i+1].Type != PORTLIST_TYPE_CPU)) + continue; // Only process cpu to cpu links + + for (j = i+2; j < pDat->TotalLinks*2; j += 2) + { + if ( (pDat->PortList[j].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[j+1].Type != PORTLIST_TYPE_CPU) ) + continue; // Only process cpu to cpu links + + if (pDat->PortList[i].NodeID != pDat->PortList[j].NodeID) + continue; // Links must be from the same source + + if (pDat->PortList[i+1].NodeID != pDat->PortList[j+1].NodeID) + continue; // Link must be to the same target + + if ((pDat->PortList[i].Link & 3) != (pDat->PortList[j].Link & 3)) + continue; // Ensure same source base port + + if ((pDat->PortList[i+1].Link & 3) != (pDat->PortList[j+1].Link & 3)) + continue; // Ensure same destination base port + + if ((pDat->PortList[i].Link & 4) != (pDat->PortList[i+1].Link & 4)) + continue; // Ensure sublink0 routes to sublink0 + + ASSERT((pDat->PortList[j].Link & 4) == (pDat->PortList[j+1].Link & 4)); // (therefore sublink1 routes to sublink1) + + if (pDat->HtBlock->AMD_CB_SkipRegang && + pDat->HtBlock->AMD_CB_SkipRegang(pDat->PortList[i].NodeID, + pDat->PortList[i].Link & 0x03, + pDat->PortList[i+1].NodeID, + pDat->PortList[i+1].Link & 0x03)) + { + continue; // Skip regang + } + + + pDat->PortList[i].Link &= 0x03; // Force to point to sublink0 + pDat->PortList[i+1].Link &= 0x03; + pDat->PortList[i].SelRegang = TRUE; // Enable link reganging + pDat->PortList[i+1].SelRegang = TRUE; + pDat->PortList[i].PrvWidthOutCap = HT_WIDTH_16_BITS; + pDat->PortList[i+1].PrvWidthOutCap = HT_WIDTH_16_BITS; + pDat->PortList[i].PrvWidthInCap = HT_WIDTH_16_BITS; + pDat->PortList[i+1].PrvWidthInCap = HT_WIDTH_16_BITS; + + // Delete PortList[j, j+1], slow but easy to debug implementation + pDat->TotalLinks--; + Amdmemcpy(&(pDat->PortList[j]), &(pDat->PortList[j+2]), sizeof(sPortDescriptor)*(pDat->TotalLinks*2-j)); + Amdmemset(&(pDat->PortList[pDat->TotalLinks*2]), INVALID_LINK, sizeof(sPortDescriptor)*2); + + ////High performance, but would make debuging harder due to 'shuffling' of the records + ////Amdmemcpy(PortList[TotalPorts-2], PortList[j], SIZEOF(sPortDescriptor)*2); + ////TotalPorts -=2; + + break; // Exit loop, advance to PortList[i+2] + } + } +#endif /* HT_BUILD_NC_ONLY */ +} + +/*---------------------------------------------------------------------------------------- + * void + * selectOptimalWidthAndFrequency(sMainData *pDat) + * + * Description: + * For all links: + * Examine both sides of a link and determine the optimal frequency and width, + * taking into account externally provided limits and enforcing any other limit + * or matching rules as applicable except sublink balancing. Update the port + * list date with the optimal settings. + * Note no hardware state changes in this routine. + * + * Parameters: + * @param[in,out] sMainData* pDat = our global state, port list data + * --------------------------------------------------------------------------------------- + */ +void selectOptimalWidthAndFrequency(sMainData *pDat) +{ + u8 i, j; + u32 temp; + u16 cbPCBFreqLimit; + u8 cbPCBABDownstreamWidth; + u8 cbPCBBAUpstreamWidth; + + for (i = 0; i < pDat->TotalLinks*2; i += 2) + { + cbPCBFreqLimit = 0xFFFF; + cbPCBABDownstreamWidth = 16; + cbPCBBAUpstreamWidth = 16; + + if ( (pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU)) + { + if (pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits) + { + pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits( + pDat->PortList[i].NodeID, + pDat->PortList[i].Link, + pDat->PortList[i+1].NodeID, + pDat->PortList[i+1].Link, + &cbPCBABDownstreamWidth, + &cbPCBBAUpstreamWidth, &cbPCBFreqLimit + ); + } + } + else + { + if (pDat->HtBlock->AMD_CB_IOPCBLimits) + { + pDat->HtBlock->AMD_CB_IOPCBLimits( + pDat->PortList[i+1].NodeID, + pDat->PortList[i+1].HostLink, + pDat->PortList[i+1].HostDepth, + &cbPCBABDownstreamWidth, + &cbPCBBAUpstreamWidth, &cbPCBFreqLimit + ); + } + } + + + temp = pDat->PortList[i].PrvFrequencyCap; + temp &= pDat->PortList[i+1].PrvFrequencyCap; + temp &= cbPCBFreqLimit; + pDat->PortList[i].CompositeFrequencyCap = (u16)temp; + pDat->PortList[i+1].CompositeFrequencyCap = (u16)temp; + + ASSERT (temp != 0); + for (j = 15; ; j--) + { + if (temp & ((u32)1 << j)) + break; + } + + pDat->PortList[i].SelFrequency = j; + pDat->PortList[i+1].SelFrequency = j; + + temp = pDat->PortList[i].PrvWidthOutCap; + if (pDat->PortList[i+1].PrvWidthInCap < temp) + temp = pDat->PortList[i+1].PrvWidthInCap; + if (cbPCBABDownstreamWidth < temp) + temp = cbPCBABDownstreamWidth; + pDat->PortList[i].SelWidthOut = (u8)temp; + pDat->PortList[i+1].SelWidthIn = (u8)temp; + + temp = pDat->PortList[i].PrvWidthInCap; + if (pDat->PortList[i+1].PrvWidthOutCap < temp) + temp = pDat->PortList[i+1].PrvWidthOutCap; + if (cbPCBBAUpstreamWidth < temp) + temp = cbPCBBAUpstreamWidth; + pDat->PortList[i].SelWidthIn = (u8)temp; + pDat->PortList[i+1].SelWidthOut = (u8)temp; + + } +} + +/*---------------------------------------------------------------------------------------- + * void + * hammerSublinkFixup(sMainData *pDat) + * + * Description: + * Iterate through all links, checking the frequency of each sublink pair. Make the + * adjustment to the port list data so that the frequencies are at a valid ratio, + * reducing frequency as needed to achieve this. (All links support the minimum 200 MHz + * frequency.) Repeat the above until no adjustments are needed. + * Note no hardware state changes in this routine. + * + * Parameters: + * @param[in,out] sMainData* pDat = our global state, link state and port list + * --------------------------------------------------------------------------------------- + */ +void hammerSublinkFixup(sMainData *pDat) +{ +#ifndef HT_BUILD_NC_ONLY + u8 i, j, k; + BOOL changes, downgrade; + + u8 hiIndex; + u8 hiFreq, loFreq; + + u32 temp; + + do + { + changes = FALSE; + for (i = 0; i < pDat->TotalLinks*2; i++) + { + if (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) // Must be a CPU link + continue; + if (pDat->PortList[i].Link < 4) // Only look for for sublink1's + continue; + + for (j = 0; j < pDat->TotalLinks*2; j++) + { + // Step 1. Find the matching sublink0 + if (pDat->PortList[j].Type != PORTLIST_TYPE_CPU) + continue; + if (pDat->PortList[j].NodeID != pDat->PortList[i].NodeID) + continue; + if (pDat->PortList[j].Link != (pDat->PortList[i].Link & 0x03)) + continue; + + // Step 2. Check for an illegal frequency ratio + if (pDat->PortList[i].SelFrequency >= pDat->PortList[j].SelFrequency) + { + hiIndex = i; + hiFreq = pDat->PortList[i].SelFrequency; + loFreq = pDat->PortList[j].SelFrequency; + } + else + { + hiIndex = j; + hiFreq = pDat->PortList[j].SelFrequency; + loFreq = pDat->PortList[i].SelFrequency; + } + + if (hiFreq == loFreq) + break; // The frequencies are 1:1, no need to do anything + + downgrade = FALSE; + + if (hiFreq == 13) + { + if ((loFreq != 7) && //{13, 7} 2400MHz / 1200MHz 2:1 + (loFreq != 4) && //{13, 4} 2400MHz / 600MHz 4:1 + (loFreq != 2) ) //{13, 2} 2400MHz / 400MHz 6:1 + downgrade = TRUE; + } + else if (hiFreq == 11) + { + if ((loFreq != 6)) //{11, 6} 2000MHz / 1000MHz 2:1 + downgrade = TRUE; + } + else if (hiFreq == 9) + { + if ((loFreq != 5) && //{ 9, 5} 1600MHz / 800MHz 2:1 + (loFreq != 2) && //{ 9, 2} 1600MHz / 400MHz 4:1 + (loFreq != 0) ) //{ 9, 0} 1600MHz / 200Mhz 8:1 + downgrade = TRUE; + } + else if (hiFreq == 7) + { + if ((loFreq != 4) && //{ 7, 4} 1200MHz / 600MHz 2:1 + (loFreq != 0) ) //{ 7, 0} 1200MHz / 200MHz 6:1 + downgrade = TRUE; + } + else if (hiFreq == 5) + { + if ((loFreq != 2) && //{ 5, 2} 800MHz / 400MHz 2:1 + (loFreq != 0) ) //{ 5, 0} 800MHz / 200MHz 4:1 + downgrade = TRUE; + } + else if (hiFreq == 2) + { + if ((loFreq != 0)) //{ 2, 0} 400MHz / 200MHz 2:1 + downgrade = TRUE; + } + else + { + downgrade = TRUE; // no legal ratios for hiFreq + } + + // Step 3. Downgrade the higher of the two frequencies, and set nochanges to FALSE + if (downgrade) + { + // Although the problem was with the port specified by hiIndex, we need to + // downgrade both ends of the link. + hiIndex = hiIndex & 0xFE; // Select the 'upstream' (i.e. even) port + + temp = pDat->PortList[hiIndex].CompositeFrequencyCap; + + // Remove hiFreq from the list of valid frequencies + temp = temp & ~((u32)1 << hiFreq); + ASSERT (temp != 0); + pDat->PortList[hiIndex].CompositeFrequencyCap = (u16)temp; + pDat->PortList[hiIndex+1].CompositeFrequencyCap = (u16)temp; + + for (k = 15; ; k--) + { + if (temp & ((u32)1 << k)) + break; + } + + pDat->PortList[hiIndex].SelFrequency = k; + pDat->PortList[hiIndex+1].SelFrequency = k; + + changes = TRUE; + } + } + } + } while (changes); // Repeat until a valid configuration is reached +#endif /* HT_BUILD_NC_ONLY */ +} + +/*---------------------------------------------------------------------------------------- + * void + * linkOptimization(sMainData *pDat) + * + * Description: + * Based on link capabilities, apply optimization rules to come up with the real best + * settings, including several external limit decision from call backs. This includes + * handling of sublinks. Finally, after the port list data is updated, set the hardware + * state for all links. + * + * Parameters: + * @param[in] sMainData* pDat = our global state + * --------------------------------------------------------------------------------------- + */ +void linkOptimization(sMainData *pDat) +{ + pDat->nb->gatherLinkData(pDat, pDat->nb); + regangLinks(pDat); + selectOptimalWidthAndFrequency(pDat); + hammerSublinkFixup(pDat); + pDat->nb->setLinkData(pDat, pDat->nb); +} + + +/*---------------------------------------------------------------------------------------- + * void + * trafficDistribution(sMainData *pDat) + * + * Description: + * In the case of a two node system with both sublinks used, enable the traffic + * distribution feature. + * + * Parameters: + * @param[in] sMainData* pDat = our global state, port list data + * --------------------------------------------------------------------------------------- + */ +void trafficDistribution(sMainData *pDat) +{ +#ifndef HT_BUILD_NC_ONLY + u32 links01, links10; + u8 linkCount; + u8 i; + + // Traffic Distribution is only used when there are exactly two nodes in the system + if (pDat->NodesDiscovered+1 != 2) + return; + + links01 = 0; + links10 = 0; + linkCount = 0; + for (i = 0; i < pDat->TotalLinks*2; i += 2) + { + if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU)) + { + links01 |= (u32)1 << pDat->PortList[i].Link; + links10 |= (u32)1 << pDat->PortList[i+1].Link; + linkCount++; + } + } + ASSERT(linkCount != 0); + if (linkCount == 1) + return; // Don't setup Traffic Distribution if only one link is being used + + pDat->nb->writeTrafficDistribution(links01, links10, pDat->nb); +#endif /* HT_BUILD_NC_ONLY */ +} + +/*---------------------------------------------------------------------------------------- + * void + * tuning(sMainData *pDat) + * + * Description: + * Handle system and performance tunings, such as traffic distribution, fifo and + * buffer tuning, and special config tunings. + * + * Parameters: + * @param[in] sMainData* pDat = our global state, port list data + * --------------------------------------------------------------------------------------- + */ +void tuning(sMainData *pDat) +{ + u8 i; + + /* See if traffic distribution can be done and do it if so + * or allow system specific customization + */ + if ((pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution == NULL) + || !pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution()) + { + trafficDistribution(pDat); + } + + /* For each node, invoke northbridge specific buffer tunings or + * system specific customizations. + */ + for (i=0; i < pDat->NodesDiscovered + 1; i++) + { + if ((pDat->HtBlock->AMD_CB_CustomizeBuffers == NULL) + || !pDat->HtBlock->AMD_CB_CustomizeBuffers(i)) + { + pDat->nb->bufferOptimizations(i, pDat, pDat->nb); + } + } +} + +/*---------------------------------------------------------------------------------------- + * BOOL + * isSanityCheckOk() + * + * Description: + * Perform any general sanity checks which should prevent HT from running if they fail. + * Currently only the "Must run on BSP only" check. + * + * Parameters: + * @param[out] result BOOL = true if check is ok, false if it failed + * --------------------------------------------------------------------------------------- + */ +BOOL isSanityCheckOk() +{ + uint64 qValue; + + AmdMSRRead(APIC_Base, &qValue); + + return ((qValue.lo & ((u32)1 << APIC_Base_BSP)) != 0); +} + +/*************************************************************************** + *** HT Initialize *** + ***************************************************************************/ + +/*---------------------------------------------------------------------------------------- + * void + * htInitialize(AMD_HTBLOCK *pBlock) + * + * Description: + * This is the top level external interface for Hypertransport Initialization. + * Create our initial internal state, initialize the coherent fabric, + * initialize the non-coherent chains, and perform any required fabric tuning or + * optimization. + * + * Parameters: + * @param[in] AMD_HTBLOCK* pBlock = Our Initial State including possible + * topologies and routings, non coherent bus + * assignment info, and actual + * wrapper or OEM call back routines. + * --------------------------------------------------------------------------------------- + */ +void amdHtInitialize(AMD_HTBLOCK *pBlock) +{ + sMainData pDat; + cNorthBridge nb; + + if (isSanityCheckOk()) + { + newNorthBridge(0, &nb); + + pDat.HtBlock = pBlock; + pDat.nb = &nb; + pDat.sysMpCap = nb.maxNodes; + nb.isCapable(0, &pDat, pDat.nb); + coherentInit(&pDat); + + pDat.AutoBusCurrent = pBlock->AutoBusStart; + pDat.UsedCfgMapEntires = 0; + ncInit(&pDat); + linkOptimization(&pDat); + tuning(&pDat); + } +} diff --git a/src/northbridge/amd/amdht/h3finit.h b/src/northbridge/amd/amdht/h3finit.h new file mode 100644 index 0000000000..8da1bd2e8c --- /dev/null +++ b/src/northbridge/amd/amdht/h3finit.h @@ -0,0 +1,613 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + +#ifndef H3FINIT_H +#define H3FINIT_H + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/* Width equates for call backs */ +#define HT_WIDTH_8_BITS 8 +#define HT_WIDTH_16_BITS 16 +#define HT_WIDTH_4_BITS 4 +#define HT_WIDTH_2_BITS 2 + +/* Frequency equates for call backs which take an actual frequency setting */ +#define HT_FREQUENCY_200M 0 +#define HT_FREQUENCY_400M 2 +#define HT_FREQUENCY_600M 4 +#define HT_FREQUENCY_800M 5 +#define HT_FREQUENCY_1000M 6 +#define HT_FREQUENCY_1200M 7 +#define HT_FREQUENCY_1400M 8 +#define HT_FREQUENCY_1600M 9 +#define HT_FREQUENCY_1800M 10 +#define HT_FREQUENCY_2000M 11 +#define HT_FREQUENCY_2200M 12 +#define HT_FREQUENCY_2400M 13 +#define HT_FREQUENCY_2600M 14 + +/* Frequency Limit equates for call backs which take a frequency supported mask. */ +#define HT_FREQUENCY_LIMIT_200M 1 +#define HT_FREQUENCY_LIMIT_400M 7 +#define HT_FREQUENCY_LIMIT_600M 0x1F +#define HT_FREQUENCY_LIMIT_800M 0x3F +#define HT_FREQUENCY_LIMIT_1000M 0x7F +#define HT_FREQUENCY_LIMIT_HT1_ONLY 0x7F +#define HT_FREQUENCY_LIMIT_1200M 0xFF +#define HT_FREQUENCY_LIMIT_1400M 0x1FF +#define HT_FREQUENCY_LIMIT_1600M 0x3FF +#define HT_FREQUENCY_LIMIT_1800M 0x7FF +#define HT_FREQUENCY_LIMIT_2000M 0xFFF +#define HT_FREQUENCY_LIMIT_2200M 0x1FFF +#define HT_FREQUENCY_LIMIT_2400M 0x3FFF +#define HT_FREQUENCY_LIMIT_2600M 0x7FFF + +/* + * Event Notify definitions + */ + +/* Event Class definitions */ +#define HT_EVENT_CLASS_CRITICAL 1 +#define HT_EVENT_CLASS_ERROR 2 +#define HT_EVENT_CLASS_HW_FAULT 3 +#define HT_EVENT_CLASS_WARNING 4 +#define HT_EVENT_CLASS_INFO 5 + +/* Event definitions. */ + +/* Coherent subfunction events */ +#define HT_EVENT_COH_EVENTS 0x1000 +#define HT_EVENT_COH_NO_TOPOLOGY 0x1001 +#define HT_EVENT_COH_LINK_EXCEED 0x1002 +#define HT_EVENT_COH_FAMILY_FEUD 0x1003 +#define HT_EVENT_COH_NODE_DISCOVERED 0x1004 +#define HT_EVENT_COH_MPCAP_MISMATCH 0x1005 + +/* Non-coherent subfunction events */ +#define HT_EVENT_NCOH_EVENTS 0x2000 +#define HT_EVENT_NCOH_BUID_EXCEED 0x2001 +#define HT_EVENT_NCOH_LINK_EXCEED 0x2002 +#define HT_EVENT_NCOH_BUS_MAX_EXCEED 0x2003 +#define HT_EVENT_NCOH_CFG_MAP_EXCEED 0x2004 +#define HT_EVENT_NCOH_DEVICE_FAILED 0x2005 +#define HT_EVENT_NCOH_AUTO_DEPTH 0x2006 + +/* Optimization subfunction events */ +#define HT_EVENT_OPT_EVENTS 0x3000 +#define HT_EVENT_OPT_REQUIRED_CAP_RETRY 0x3001 +#define HT_EVENT_OPT_REQUIRED_CAP_GEN3 0x3002 + +/* HW Fault events */ +#define HT_EVENT_HW_EVENTS 0x4000 +#define HT_EVENT_HW_SYNCHFLOOD 0x4001 +#define HT_EVENT_HW_HTCRC 0x4002 + +/* The bbHT component (hb*) uses 0x5000 for events. + * For consistency, we avoid that range here. + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +typedef struct { + u8 **topolist; + u8 AutoBusStart; + /* Note: This should always be the form AutoBusCurrent+N*AutoBusIncrement, also bus 253-255 are reserved */ + u8 AutoBusMax; + u8 AutoBusIncrement; + + /**---------------------------------------------------------------------------------------- + * + * BOOL + * AMD_CB_IgnoreLink(u8 Node, u8 Link) + * + * Description: + * This routine is called every time a coherent link is found and then every + * time a non-coherent link from a CPU is found. + * Any coherent or non-coherent link from a CPU can be ignored and not used + * for discovery or initialization. Useful for connection based systems. + * (Note: not called for IO device to IO Device links.) + * + * Parameters: + * @param[in] u8 node = The node on which this link is located + * @param[in] u8 link = The link about to be initialized + * @param[out] BOOL result = true to ignore this link and skip it + * false to initialize the link normally + * + * --------------------------------------------------------------------------------------- + */ + BOOL (*AMD_CB_IgnoreLink)(u8 Node, u8 Link); + + /**---------------------------------------------------------------------------------------- + * + * BOOL + * AMD_CB_OverrideBusNumbers(u8 Node, u8 Link, u8 *SecBus, u8 *SubBus) + * + * Description: + * This routine is called every time a non-coherent chain is processed. + * If a system can not use the auto Bus numbering feature for non-coherent chain bus + * assignments, this routine can provide explicit control. For each chain, provide + * the bus number range to use. + * + * Parameters: + * @param[in] u8 node = The node on which this chain is located + * @param[in] u8 link = The link on the host for this chain + * @param[out] u8 secBus = Secondary Bus number for this non-coherent chain + * @param[out] u8* subBus = Subordinate Bus number + * @param[out] BOOL result = true this routine is supplying the bus numbers + * false use auto Bus numbering + * + * --------------------------------------------------------------------------------------- + */ + BOOL (*AMD_CB_OverrideBusNumbers)(u8 Node, u8 Link, u8 *SecBus, u8 *SubBus); + + /**---------------------------------------------------------------------------------------- + * + * BOOL + * AMD_CB_ManualBUIDSwapList(u8 Node, u8 Link, u8 **List) + * + * Description: + * This routine is called every time a non-coherent chain is processed. + * BUID assignment may be controlled explicitly on a non-coherent chain. Provide a + * swap list. The first part of the list controls the BUID assignment and the + * second part of the list provides the device to device linking. Device orientation + * can be detected automatically, or explicitly. See documentation for more details. + * + * Automatic non-coherent init assigns BUIDs starting at 1 and incrementing sequentially + * based on each device's unit count. + * + * Parameters: + * @param[in] u8 node = The node on which this chain is located + * @param[in] u8 link = The link on the host for this chain + * @param[out] u8** list = supply a pointer to a list + * @param[out] BOOL result = true to use a manual list + * false to initialize the link automatically + * + * --------------------------------------------------------------------------------------- + */ + BOOL (*AMD_CB_ManualBUIDSwapList)(u8 Node, u8 Link, u8 **List); + + /**---------------------------------------------------------------------------------------- + * + * void + * AMD_CB_DeviceCapOverride(u8 HostNode, u8 HostLink, u8 Depth, u8 Segment, + * u8 Bus, u8 Dev, u32 DevVenID, u8 Link, + * u8 *LinkWidthIn, u8 *LinkWidthOut, u16 *FreqCap) + * + * Description: + * This routine is called once for every link on every IO device. + * Update the width and frequency capability if needed for this device. + * This is used along with device capabilities, the limit call backs, and northbridge + * limits to compute the default settings. The components of the device's PCI config + * address are provided, so its settings can be consulted if need be. The input width + * and frequency are the reported device capabilities. + * + * Parameters: + * @param[in] u8 hostNode = The node on which this chain is located + * @param[in] u8 hostLink = The link on the host for this chain + * @param[in] u8 Depth = The depth in the I/O chain from the Host + * @param[in] u8 Segment = The Device's PCI Bus Segment number + * @param[in] u8 Bus = The Device's PCI Bus number + * @param[in] u8 Dev = The Device's PCI device Number + * @param[in] u32 DevVenID = The Device's PCI Vendor + Device ID (offset 0x00) + * @param[in] u8 Link = The Device's link number (0 or 1) + * @param[in,out] u8* LinkWidthIn = modify to change the Link Witdh In + * @param[in,out] u8* LinkWidthOut = modify to change the Link Witdh Out + * @param[in,out] u16* FreqCap = modify to change the link's frequency capability + * + * --------------------------------------------------------------------------------------- + */ + void (*AMD_CB_DeviceCapOverride)( + u8 HostNode, + u8 HostLink, + u8 Depth, + u8 Segment, + u8 Bus, + u8 Dev, + u32 DevVenID, + u8 Link, + u8 *LinkWidthIn, + u8 *LinkWidthOut, + u16 *FreqCap + ); + + /**---------------------------------------------------------------------------------------- + * + * void + * AMD_CB_Cpu2CpuPCBLimits(u8 NodeA, u8 LinkA, u8 NodeB, u8 LinkB, + * u8 *ABLinkWidthLimit, u8 *BALinkWidthLimit, u16 *PCBFreqCap) + * + * Description: + * For each coherent connection this routine is called once. + * Update the frequency and width if needed for this link (usually based on board + * restriction). This is used with CPU device capabilities and northbridge limits + * to compute the default settings. The input width and frequency are valid, but do + * not necessarily reflect the minimum setting that will be chosen. + * + * Parameters: + * @param[in] u8 nodeA = One node on which this link is located + * @param[in] u8 linkA = The link on this node + * @param[in] u8 nodeB = The other node on which this link is located + * @param[in] u8 linkB = The link on that node + * @param[in,out] u8* ABLinkWidthLimit = modify to change the Link Witdh In + * @param[in,out] u8* BALinkWidthLimit = modify to change the Link Witdh Out + * @param[in,out] u16* PCBFreqCap = modify to change the link's frequency capability + * + * --------------------------------------------------------------------------------------- + */ + void (*AMD_CB_Cpu2CpuPCBLimits)( + u8 NodeA, + u8 LinkA, + u8 NodeB, + u8 LinkB, + u8 *ABLinkWidthLimit, + u8 *BALinkWidthLimit, + u16 *PCBFreqCap + ); + + /**---------------------------------------------------------------------------------------- + * + * void + * AMD_CB_IOPCBLimits(u8 HostNode, u8 HostLink, u8 Depth, u8 *DownstreamLinkWidthLimit, + * u8 *UpstreamLinkWidthLimit, u16 *PCBFreqCap) + * + * Description: + * For each non-coherent connection this routine is called once. + * Update the frequency and width if needed for this link (usually based on board + * restriction). This is used with device capabilities, device overrides, and northbridge limits + * to compute the default settings. The input width and frequency are valid, but do + * not necessarily reflect the minimum setting that will be chosen. + * + * Parameters: + * @param[in] u8 hostNode = The node on which this link is located + * @param[in] u8 hostLink = The link about to be initialized + * @param[in] u8 Depth = The depth in the I/O chain from the Host + * @param[in,out] u8* DownstreamLinkWidthLimit = modify to change the Link Witdh In + * @param[in,out] u8* UpstreamLinkWidthLimit = modify to change the Link Witdh Out + * @param[in,out] u16* PCBFreqCap = modify to change the link's frequency capability + * + * --------------------------------------------------------------------------------------- + */ + void (*AMD_CB_IOPCBLimits)( + u8 HostNode, + u8 HostLink, + u8 Depth, + u8 *DownstreamLinkWidthLimit, + u8 *UpstreamLinkWidthLimit, + u16 *PCBFreqCap + ); + + /**---------------------------------------------------------------------------------------- + * + * BOOL + * AMD_CB_SkipRegang(u8 NodeA, u8 LinkA, u8 NodeB, u8 LinkB) + * + * Description: + * This routine is called whenever two sublinks are both connected to the same CPUs. + * Normally, unganged subsinks between the same two CPUs are reganged. + * Return true from this routine to leave the links unganged. + * + * Parameters: + * @param[in] u8 nodeA = One node on which this link is located + * @param[in] u8 linkA = The link on this node + * @param[in] u8 nodeB = The other node on which this link is located + * @param[in] u8 linkB = The link on that node + * @param[out] BOOL result = true to leave link unganged + * false to regang link automatically + * + * --------------------------------------------------------------------------------------- + */ + BOOL (*AMD_CB_SkipRegang)( + u8 NodeA, + u8 LinkA, + u8 NodeB, + u8 LinkB + ); + + /**---------------------------------------------------------------------------------------- + * + * BOOL + * AMD_CB_CustomizeTrafficDistribution() + * + * Description: + * Near the end of HT initialization, this routine is called once. + * If this routine will handle traffic distribution in a proprietary way, + * after detecting which links to distribute traffic on and configuring the system, + * return true. Return false to let the HT code detect and do traffic distribution + * This routine can also be used to simply turn this feature off, or to pre-process + * the system before normal traffic distribution. + * + * Parameters: + * @param[out] BOOL result = true skip traffic distribution + * false do normal traffic distribution + * + * --------------------------------------------------------------------------------------- + */ + BOOL (*AMD_CB_CustomizeTrafficDistribution)(); + + + /**---------------------------------------------------------------------------------------- + * + * BOOL + * AMD_CB_CustomizeBuffers(u8 Node) + * + * Description: + * Near the end of HT initialization, this routine is called once per CPU node. + * Implement proprietary buffer tuning and return true, or return false for normal tuning. + * This routine can also be used to simply turn this feature off, or to pre-process + * the system before normal tuning. + * + * Parameters: + * @param[in] u8 node = buffer allocation may apply to this node + * @param[out] BOOL result = true skip buffer allocation on this node + * false tune buffers normally + * + * --------------------------------------------------------------------------------------- + */ + BOOL (*AMD_CB_CustomizeBuffers)( u8 node ); + + /**---------------------------------------------------------------------------------------- + * + * void + * AMD_CB_OverrideDevicePort(u8 HostNode, u8 HostLink, u8 Depth, u8 *LinkWidthIn, + * u8 *LinkWidthOut, u16 *LinkFrequency) + * + * Description: + * Called once for each active link on each IO device. + * Provides an opportunity to directly control the frequency and width, + * intended for test and debug. The input frequency and width will be used + * if not overridden. + * + * Parameters: + * @param[in] u8 hostNode = The node on which this link is located + * @param[in] u8 hostLink = The link about to be initialized + * @param[in] u8 Depth = The depth in the I/O chain from the Host + * @param[in] u8 Link = the link on the device (0 or 1) + * @param[in,out] u8* LinkWidthIn = modify to change the Link Witdh In + * @param[in,out] u8* LinkWidthOut = modify to change the Link Witdh Out + * @param[in,out] u16* LinkFrequency = modify to change the link's frequency capability + * + * --------------------------------------------------------------------------------------- + */ + void (*AMD_CB_OverrideDevicePort)( + u8 HostNode, + u8 HostLink, + u8 Depth, + u8 Link, + u8 *LinkWidthIn, + u8 *LinkWidthOut, + u8 *LinkFrequency + ); + + /**---------------------------------------------------------------------------------------- + * + * void + * AMD_CB_OverrideCpuPort(u8 Node, u8 Link, u8 *LinkWidthIn, u8 *LinkWidthOut, + * u16 *LinkFrequency) + * + * Description: + * Called once for each active link on each CPU. + * Provides an opportunity to directly control the frequency and width, + * intended for test and debug. The input frequency and width will be used + * if not overridden. + * + * Parameters: + * @param[in] u8 node = One node on which this link is located + * @param[in] u8 link = The link on this node + * @param[in,out] u8* LinkWidthIn = modify to change the Link Witdh In + * @param[in,out] u8* LinkWidthOut = modify to change the Link Witdh Out + * @param[in,out] u16* LinkFrequency = modify to change the link's frequency capability + * + *--------------------------------------------------------------------------------------- + */ + void (*AMD_CB_OverrideCpuPort)( + u8 Node, + u8 Link, + u8 *LinkWidthIn, + u8 *LinkWidthOut, + u8 *LinkFrequency + ); + + /**---------------------------------------------------------------------------------------- + * + * void + * AMD_CB_EventNotify(u8 evtClass, u16 event, const u8 *pEventData0) + * + * Description: + * Errors, events, faults, warnings, and useful information are provided by + * calling this routine as often as necessary, once for each notification. + * See elsewhere in this file for class, event, and event data definitions. + * See the documentation for more details. + * + * Parameters: + * @param[in] u8 evtClass = What level event is this + * @param[in] u16 event = A unique ID of this event + * @param[in] u8* pEventData0 = useful data associated with the event. + * + * --------------------------------------------------------------------------------------- + */ + void (*AMD_CB_EventNotify) ( + u8 evtClass, + u16 event, + const u8 *pEventData0 + ); + +} AMD_HTBLOCK; + +/* + * Event Notification Structures + * These structures are passed to AMD_CB_EventNotify as *pEventData0. + */ + +/* For event HT_EVENT_HW_SYNCHFLOOD */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; +} sHtEventHWSynchFlood; + +/* For event HT_EVENT_HW_HTCRC */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 laneMask; +} sHtEventHWHtCrc; + +/* For event HT_EVENT_NCOH_BUS_MAX_EXCEED */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 bus; +} sHTEventNcohBusMaxExceed; + +/* For event HT_EVENT_NCOH_LINK_EXCEED */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 depth; + u8 maxLinks; +} sHtEventNcohLinkExceed; + +/* For event HT_EVENT_NCOH_CFG_MAP_EXCEED */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; +} sHtEventNcohCfgMapExceed; + +/* For event HT_EVENT_NCOH_BUID_EXCEED */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 depth; + u8 currentBUID; + u8 unitCount; +} sHtEventNcohBuidExceed; + +/* For event HT_EVENT_NCOH_DEVICE_FAILED */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 depth; + u8 attemptedBUID; +} sHtEventNcohDeviceFailed; + +/* For event HT_EVENT_NCOH_AUTO_DEPTH */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 depth; +} sHtEventNcohAutoDepth; + +/* For event HT_EVENT_OPT_REQUIRED_CAP_RETRY, + * HT_EVENT_OPT_REQUIRED_CAP_GEN3 + */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 depth; +} sHtEventOptRequiredCap; + +/* For event HT_EVENT_COH_NO_TOPOLOGY */ +typedef struct +{ + u8 eSize; + u8 totalNodes; +} sHtEventCohNoTopology; + +/* For event HT_EVENT_COH_LINK_EXCEED */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 targetNode; + u8 totalNodes; + u8 maxLinks; +} sHtEventCohLinkExceed; + +/* For event HT_EVENT_COH_FAMILY_FEUD */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 totalNodes; +} sHtEventCohFamilyFeud; + +/* For event HT_EVENT_COH_NODE_DISCOVERED */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 newNode; +} sHtEventCohNodeDiscovered; + +/* For event HT_EVENT_COH_MPCAP_MISMATCH */ +typedef struct +{ + u8 eSize; + u8 node; + u8 link; + u8 sysMpCap; + u8 totalNodes; +} sHtEventCohMpCapMismatch; + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ +void amdHtInitialize(AMD_HTBLOCK *pBlock); + + +#endif /* H3FINIT_H */ + + diff --git a/src/northbridge/amd/amdht/h3gtopo.h b/src/northbridge/amd/amdht/h3gtopo.h new file mode 100644 index 0000000000..a724618763 --- /dev/null +++ b/src/northbridge/amd/amdht/h3gtopo.h @@ -0,0 +1,358 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + +#ifndef HTTOPO_H +#define HTTOPO_H + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +/* + * 0 + */ +static u8 const amdHtTopologySingleNode[] = { + 0x01, + 0x00, 0xFF // Node 0 +}; + +/* + * 0---1 + */ +static u8 const amdHtTopologyDualNode[] = { + 0x02, + 0x02, 0xFF, 0x00, 0x11, // Node 0 + 0x00, 0x00, 0x01, 0xFF // Node 1 +}; + +/* + * 2 + * | + * | + * 0---1 + */ +static u8 const amdHtTopologyThreeLine[] = { + 0x03, + 0x06, 0xFF, 0x04, 0x11, 0x02, 0x22, // Node 0 + 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, // Node 1 + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF // Node 2 +}; + +/* + * 2 + * |\ + * | \ + * 0---1 + */ +static u8 const amdHtTopologyTriangle[] = { + 0x03, + 0x06, 0xFF, 0x00, 0x11, 0x00, 0x22, // Node 0 + 0x00, 0x00, 0x05, 0xFF, 0x00, 0x22, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0x03, 0xFF // Node 2 +}; + +/* + * 2 3 + * |\ | + * | \| + * 0---1 + */ +static u8 const amdHtTopologyFourDegenerate[] = { + 0x04, + 0x06, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x11, // Node 0 + 0x08, 0x00, 0x0D, 0xFF, 0x08, 0x22, 0x05, 0x33, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0x03, 0xFF, 0x00, 0x11, // Node 2 + 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x02, 0xFF // Node 3 +}; + +/* + * 2---3 + * |\ /| + * |/ \| + * 0---1 + */ +static u8 const amdHtTopologyFourFully[] = { + 0x04, + 0x0E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, // Node 0 + 0x00, 0x00, 0x0D, 0xFF, 0x00, 0x22, 0x00, 0x33, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0x0B, 0xFF, 0x00, 0x33, // Node 2 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x07, 0xFF // Node 3 +}; + + +/* + * 2---3 + * |\ | + * | \| + * 0---1 + */ +static u8 const amdHtTopologyFourKite[] = { + 0x04, + 0x06, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x11, // Node 0 + 0x08, 0x00, 0x0D, 0xFF, 0x00, 0x22, 0x00, 0x33, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0x0B, 0xFF, 0x01, 0x33, // Node 2 + 0x00, 0x22, 0x00, 0x11, 0x00, 0x22, 0x06, 0xFF // Node 3 +}; + + +/* + * 2 3 + * | | + * | | + * 0---1 + */ +static u8 const amdHtTopologyFourLine[] = { + 0x04, + 0x06, 0xFF, 0x04, 0x11, 0x02, 0x22, 0x04, 0x11, // Node 0 + 0x08, 0x00, 0x09, 0xFF, 0x08, 0x00, 0x01, 0x33, // Node 1 + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, // Node 2 + 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x02, 0xFF // Node 3 +}; + + +/* + * 2---3 + * | | + * | | + * 0---1 + */ +static u8 const amdHtTopologyFourSquare[] = { + 0x04, + 0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x22, // Node 0 + 0x00, 0x00, 0x09, 0xFF, 0x00, 0x33, 0x01, 0x33, // Node 1 + 0x08, 0x00, 0x00, 0x00, 0x09, 0xFF, 0x00, 0x33, // Node 2 + 0x00, 0x11, 0x04, 0x11, 0x00, 0x22, 0x06, 0xFF, // Node 3 +}; + + +/* + * 2---3 + * |\ + * | \ + * 0 1 + */ +static u8 const amdHtTopologyFourStar[] = { + 0x04, + 0x04, 0xFF, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, // Node 0 + 0x00, 0x22, 0x04, 0xFF, 0x00, 0x22, 0x00, 0x22, // Node 1 + 0x0A, 0x00, 0x09, 0x11, 0x0B, 0xFF, 0x03, 0x33, // Node 2 + 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x04, 0xFF, // Node 3 +}; + + +static u8 const amdHtTopologyFiveFully[] = { + 0x05, + 0x1E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, // Node 0 + 0x00, 0x00, 0x1D, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0x1B, 0xFF, 0x00, 0x33, 0x00, 0x44, // Node 2 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x17, 0xFF, 0x00, 0x44, // Node 3 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x0F, 0xFF // Node 4 +}; + + +/* + * + * 4 + * |\ + * | \ + * 2 3 + * | | + * 0---1 + */ +static u8 const amdHtTopologyFiveTwistedLadder[] = { + 0x05, + 0x06, 0xFF, 0x04, 0x11, 0x02, 0x22, 0x00, 0x11, 0x00, 0x22, // Node0 + 0x08, 0x00, 0x09, 0xFF, 0x08, 0x00, 0x01, 0x33, 0x00, 0x30, // Node1 + 0x10, 0x00, 0x10, 0x00, 0x11, 0xFF, 0x00, 0x40, 0x01, 0x44, // Node2 + 0x00, 0x11, 0x00, 0x11, 0x00, 0x14, 0x12, 0xFF, 0x02, 0x44, // Node3 + 0x00, 0x22, 0x00, 0x23, 0x00, 0x22, 0x04, 0x33, 0x0C, 0xFF // Node4 +}; + + +static u8 const amdHtTopologySixFully[] = { + 0x06, + 0x3E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, // Node 0 + 0x00, 0x00, 0x3D, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0x3B, 0xFF, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, // Node 2 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x37, 0xFF, 0x00, 0x44, 0x00, 0x55, // Node 3 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x2F, 0xFF, 0x00, 0x55, // Node 4 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x1F, 0xFF // Node 5 +}; + +/* + * + * 4 5 + * |\ /| + * |/ \| + * 2 3 + * | | + * 0---1 + */ +static u8 const amdHtTopologySixTwistedLadder[] = { + 0x06, + 0x06, 0xFF, 0x04, 0x11, 0x02, 0x22, 0x00, 0x11, 0x02, 0x22, 0x00, 0x12, // Node0 + 0x08, 0x00, 0x09, 0xFF, 0x00, 0x00, 0x01, 0x33, 0x00, 0x03, 0x01, 0x33, // Node1 + 0x30, 0x00, 0x00, 0x00, 0x31, 0xFF, 0x00, 0x54, 0x21, 0x44, 0x00, 0x55, // Node2 + 0x00, 0x11, 0x30, 0x11, 0x00, 0x45, 0x32, 0xFF, 0x00, 0x44, 0x12, 0x55, // Node3 + 0x00, 0x22, 0x00, 0x32, 0x08, 0x22, 0x00, 0x33, 0x0C, 0xFF, 0x00, 0x32, // Node4 + 0x00, 0x23, 0x00, 0x33, 0x00, 0x22, 0x04, 0x33, 0x00, 0x23, 0x0C, 0xFF // Node5 +}; + + +static u8 const amdHtTopologySevenFully[] = { + 0x07, + 0x7E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, // Node 0 + 0x00, 0x00, 0x7D, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0x7B, 0xFF, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, // Node 2 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x77, 0xFF, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, // Node 3 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x6F, 0xFF, 0x00, 0x55, 0x00, 0x66, // Node 4 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x5F, 0xFF, 0x00, 0x66, // Node 5 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x3F, 0xFF, // Node 6 +}; + + +/* 6 + * | + * 4 5 + * |\ /| + * |/ \| + * 2 3 + * | | + * 0---1 + */ +static u8 const amdHtTopologySevenTwistedLadder[] = { + 0x07, + 0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x12, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, // Node0 + 0x00, 0x00, 0x09, 0xFF, 0x00, 0x03, 0x01, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, // Node1 + 0x30, 0x00, 0x00, 0x50, 0x31, 0xFF, 0x00, 0x54, 0x21, 0x44, 0x01, 0x55, 0x21, 0x44, // Node2 + 0x00, 0x41, 0x30, 0x11, 0x00, 0x45, 0x32, 0xFF, 0x02, 0x44, 0x12, 0x55, 0x02, 0x44, // Node3 + 0x48, 0x22, 0x40, 0x33, 0x48, 0x22, 0x40, 0x33, 0x4C, 0xFF, 0x40, 0x32, 0x0C, 0x66, // Node4 + 0x00, 0x22, 0x04, 0x33, 0x00, 0x22, 0x04, 0x33, 0x00, 0x23, 0x0C, 0xFF, 0x00, 0x23, // Node5 + 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x10, 0xFF // Node6 +}; + + +/* + * 5--4 + * /####\ + * 6######3 + * |######| + * 7######2 + * \####/ + * 0--1 + */ +static u8 const amdHtTopologyEightFully [] = { + 0x08, + 0xFE, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77, // Node 0 + 0x00, 0x00, 0xFD, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77, // Node 1 + 0x00, 0x00, 0x00, 0x11, 0xFB, 0xFF, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77, // Node 2 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0xF7, 0xFF, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77, // Node 3 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0xEF, 0xFF, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77, // Node 4 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0xDF, 0xFF, 0x00, 0x66, 0x00, 0x77, // Node 5 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0xBF, 0xFF, 0x00, 0x77, // Node 6 + 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x7F, 0xFF // Node 7 +}; + + +/* 6---7 + * | | + * 4---5 + * | | + * 2---3 + * | | + * 0---1 + */ +static u8 const amdHtTopologyEightStraightLadder[] = { + 0x08, + 0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x22, 0x02, 0x22, 0x00, 0x22, 0x02, 0x22, 0x00, 0x22, // Node0 + 0x00, 0x00, 0x09, 0xFF, 0x00, 0x33, 0x01, 0x33, 0x00, 0x33, 0x01, 0x33, 0x00, 0x33, 0x01, 0x33, // Node1 + 0x18, 0x00, 0x00, 0x00, 0x19, 0xFF, 0x00, 0x33, 0x09, 0x44, 0x00, 0x44, 0x09, 0x44, 0x00, 0x44, // Node2 + 0x00, 0x11, 0x24, 0x11, 0x00, 0x22, 0x26, 0xFF, 0x00, 0x55, 0x06, 0x55, 0x00, 0x55, 0x06, 0x55, // Node3 + 0x60, 0x22, 0x00, 0x22, 0x60, 0x22, 0x00, 0x22, 0x64, 0xFF, 0x00, 0x55, 0x24, 0x66, 0x00, 0x66, // Node4 + 0x00, 0x33, 0x90, 0x33, 0x00, 0x33, 0x90, 0x33, 0x00, 0x44, 0x98, 0xFF, 0x00, 0x77, 0x18, 0x77, // Node5 + 0x80, 0x44, 0x00, 0x44, 0x80, 0x44, 0x00, 0x44, 0x80, 0x44, 0x00, 0x44, 0x90, 0xFF, 0x00, 0x77, // Node6 + 0x00, 0x55, 0x40, 0x55, 0x00, 0x55, 0x40, 0x55, 0x00, 0x55, 0x40, 0x55, 0x00, 0x66, 0x60, 0xFF // Node7 +}; + + +/* 6---7 + * | | + * 4 5 + * |\ /| + * |/ \| + * 2 3 + * | | + * 0---1 + */ +static u8 const amdHtTopologyEightTwistedLadder[] = { + 0x08, + 0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x12, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, // Node0 + 0x00, 0x00, 0x09, 0xFF, 0x00, 0x03, 0x01, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, // Node1 + 0x30, 0x00, 0x00, 0x50, 0x31, 0xFF, 0x00, 0x54, 0x21, 0x44, 0x01, 0x55, 0x21, 0x44, 0x01, 0x55, // Node2 + 0x00, 0x41, 0x30, 0x11, 0x00, 0x45, 0x32, 0xFF, 0x02, 0x44, 0x12, 0x55, 0x02, 0x44, 0x12, 0x55, // Node3 + 0x48, 0x22, 0x40, 0x33, 0x48, 0x22, 0x40, 0x33, 0x4C, 0xFF, 0x00, 0x32, 0x0C, 0x66, 0x00, 0x36, // Node4 + 0x80, 0x22, 0x84, 0x33, 0x80, 0x22, 0x84, 0x33, 0x00, 0x23, 0x8C, 0xFF, 0x00, 0x27, 0x0C, 0x77, // Node5 + 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x80, 0x44, 0x00, 0x74, 0x90, 0xFF, 0x00, 0x77, // Node6 + 0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x65, 0x40, 0x55, 0x00, 0x66, 0x60, 0xFF // Node7 +}; + +static const u8 * const amd_topo_list[] = { + amdHtTopologySingleNode, + amdHtTopologyDualNode, + amdHtTopologyThreeLine, + amdHtTopologyTriangle, + amdHtTopologyFourLine, + amdHtTopologyFourStar, + amdHtTopologyFourDegenerate, + amdHtTopologyFourSquare, + amdHtTopologyFourKite, + amdHtTopologyFourFully, + amdHtTopologyFiveFully, + amdHtTopologySixFully, + amdHtTopologySevenFully, + amdHtTopologyEightFully, + amdHtTopologyEightTwistedLadder, + amdHtTopologyEightStraightLadder, + NULL // NULL to mark end of list +}; + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ +void getAmdTopolist(u8 ***p); + + +#endif /* HTTOPO_H */ + diff --git a/src/northbridge/amd/amdht/h3ncmn.c b/src/northbridge/amd/amdht/h3ncmn.c new file mode 100644 index 0000000000..f03139f914 --- /dev/null +++ b/src/northbridge/amd/amdht/h3ncmn.c @@ -0,0 +1,2214 @@ +/* + * This file is part of the LinuxBIOS 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 = {sizeof(sHtEventHWHtCrc), node, link, (u8)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 = {sizeof(sHtEventHWSynchFlood), node, 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; i<cores; i++) + { + if (leveling & ((u32) 1 << i)) + { + temp--; + } + } + return (u8)(temp+1); +} + +/**---------------------------------------------------------------------------------------- + * + * 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 + * + * --------------------------------------------------------------------------------------- + */ +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); +} + +/**---------------------------------------------------------------------------------------- + * + * 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 + + return 0xFF; // make the compiler happy. + +} + +/**---------------------------------------------------------------------------------------- + * + * 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 + + return 0xFF; // make the compiler happy. +} + +/**---------------------------------------------------------------------------------------- + * + * 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 ={sizeof(sHtEventOptRequiredCap), + pDat->PortList[i].NodeID, + pDat->PortList[i].HostLink, + 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 ={sizeof(sHtEventOptRequiredCap), + pDat->PortList[i].NodeID, + pDat->PortList[i].HostLink, + 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); +} + diff --git a/src/northbridge/amd/amdht/h3ncmn.h b/src/northbridge/amd/amdht/h3ncmn.h new file mode 100644 index 0000000000..51f82bff6f --- /dev/null +++ b/src/northbridge/amd/amdht/h3ncmn.h @@ -0,0 +1,132 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + +#ifndef H3NCMN_H +#define H3NCMN_H + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/* Use a macro to convert a node number to a PCI device. If some future port of + * this code needs to, this can easily be replaced by a function call: + * u8 makePCIDeviceFromNode(u8 node); + */ +#define makePCIDeviceFromNode(node) \ + ((u8)(24 + node)) + +/* Use a macro to convert a node number to a PCI bus. If some future port of + * this code needs to, this can easily be replaced by a function call: + * u8 makePCIBusFromNode(u8 node); + */ +#define makePCIBusFromNode(node) \ + ((u8)(0)) + +/* Use a macro to convert a node number to a PCI Segment. If some future port of + * this code needs to, this can easily be replaced by a function call: + * u8 makePCISegmentFromNode(u8 node); + */ +#define makePCISegmentFromNode(node) \ + ((u8)(0)) + +/* Macros to fix support issues that come up with early sample processors, which + * sometimes do things like report capabilities that are actually unsupported. + * Use the build flag, HT_BUILD_EARLY_SAMPLE_CPU_SUPPORT, to enable this support. + * + * It's not envisioned this would be replaced by an external function, but the prototype is + * u16 fixEarlySampleFreqCapability(u16 fc); + */ +#ifndef HT_BUILD_EARLY_SAMPLE_CPU_SUPPORT +#define fixEarlySampleFreqCapability(fc) \ + ((u16)fc) +#else +#define fixEarlySampleFreqCapability(fc) \ + ((u16)fc & HT_FREQUENCY_LIMIT_HT1_ONLY) +#endif + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +struct cNorthBridge +{ + /* Public data, clients of northbridge can access */ + u8 maxLinks; + u8 maxNodes; + u8 maxPlatformLinks; + + /* Public Interfaces for northbridge clients, coherent init*/ + void (*writeRoutingTable)(u8 node, u8 target, u8 link, cNorthBridge *nb); + void (*writeNodeID)(u8 node, u8 nodeID, cNorthBridge *nb); + u8 (*readDefLnk)(u8 node, cNorthBridge *nb); + void (*enableRoutingTables)(u8 node, cNorthBridge *nb); + BOOL (*verifyLinkIsCoherent)(u8 node, u8 link, cNorthBridge *nb); + BOOL (*readTrueLinkFailStatus)(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb); + u8 (*readToken)(u8 node, cNorthBridge *nb); + void (*writeToken)(u8 node, u8 value, cNorthBridge *nb); + u8 (*getNumCoresOnNode)(u8 node, cNorthBridge *nb); + void (*setTotalNodesAndCores)(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb); + void (*limitNodes)(u8 node, cNorthBridge *nb); + void (*writeFullRoutingTable)(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 bClinks, cNorthBridge *nb); + BOOL (*isCompatible)(u8 node, cNorthBridge *nb); + BOOL (*isCapable)(u8 node, sMainData *pDat, cNorthBridge *nb); + void (*stopLink)(u8 node, u8 link, cNorthBridge *nb); + BOOL (*handleSpecialLinkCase)(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb); + + /* Public Interfaces for northbridge clients, noncoherent init */ + u8 (*readSbLink)(cNorthBridge *nb); + BOOL (*verifyLinkIsNonCoherent)(u8 node, u8 link, cNorthBridge *nb); + void (*setCFGAddrMap)(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb); + + /* Public Interfaces for northbridge clients, Optimization */ + u8 (*convertBitsToWidth)(u8 value, cNorthBridge *nb); + u8 (*convertWidthToBits)(u8 value, cNorthBridge *nb); + u16 (*northBridgeFreqMask)(u8 node, cNorthBridge *nb); + void (*gatherLinkData)(sMainData *pDat, cNorthBridge *nb); + void (*setLinkData)(sMainData *pDat, cNorthBridge *nb); + + /* Public Interfaces for northbridge clients, System and performance Tuning. */ + void (*writeTrafficDistribution)(u32 links01, u32 links10, cNorthBridge *nb); + void (*bufferOptimizations)(u8 node, sMainData *pDat, cNorthBridge *nb); + + /* Private Data for northbridge implementation use only */ + u32 selfRouteRequestMask; + u32 selfRouteResponseMask; + u8 broadcastSelfBit; + u32 compatibleKey; +} ; + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ +void newNorthBridge(u8 node, cNorthBridge *nb); + +#endif /* H3NCMN_H */ diff --git a/src/northbridge/amd/amdht/ht_wrapper.c b/src/northbridge/amd/amdht/ht_wrapper.c new file mode 100644 index 0000000000..6892c63e45 --- /dev/null +++ b/src/northbridge/amd/amdht/ht_wrapper.c @@ -0,0 +1,160 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + + +/*---------------------------------------------------------------------------- + * TYPEDEFS, DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/* Single CPU system? */ +#if (CONFIG_MAX_PHYSICAL_CPUS == 1) + #define HT_BUILD_NC_ONLY 1 +#endif + +/* Debugging Options */ +#define AMD_DEBUG 1 +//#define AMD_DEBUG_ERROR_STOP 1 + +/*---------------------------------------------------------------------------- + * MODULES USED + * + *---------------------------------------------------------------------------- + */ + +#undef FILECODE +#define FILECODE 0xFF01 +#include "comlib.h" +#include "h3gtopo.h" +#include "h3finit.h" + +/* include the main HT source file */ +#include "h3finit.c" + + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* FIXME: Find a better place for these pre-ram functions. */ +#define NODE_HT(x) NODE_PCI(x,0) +#define NODE_MP(x) NODE_PCI(x,1) +#define NODE_MC(x) NODE_PCI(x,3) +#define NODE_LC(x) NODE_PCI(x,4) +static u32 get_nodes(void) +{ + device_t dev; + u32 nodes; + + dev = PCI_DEV(CBB, CDB, 0); + nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) ; +#if CONFIG_MAX_PHYSICAL_CPUS > 8 + nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3); +#endif + nodes++; + + return nodes; +} + +static void enable_apic_ext_id(u32 node) +{ + u32 val; + val = pci_read_config32(NODE_HT(node), 0x68); + val |= (HTTC_APIC_EXT_SPUR | HTTC_APIC_EXT_ID | HTTC_APIC_EXT_BRD_CST); + pci_write_config32(NODE_HT(node), 0x68, val); +} + + +static void setup_link_trans_cntrl() +{ + /* FIXME: Not sure that this belongs here but it is HT related */ + u32 val; + val = pci_read_config32(NODE_HT(0), 0x68); + val |= 0x00206800; // DSNpReqLimit, LimitCldtCfg, BufRefPri, RespPassPW per BKDG; + pci_write_config32(NODE_HT(0), 0x68, val); +} + + + + +/** + * void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0) + * + * Needs to be fixed to output the debug structures. + * + */ +void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0) +{ + printk_debug("AMD_CB_EventNotify()\n"); + printk_debug("event class: %02x event: %04x\n", evtClass, event); + +} + +/** + * void getAmdTopolist(u8 ***p) + * + * point to the stock topo list array + * + */ +void getAmdTopolist(u8 ***p) +{ + *p = (u8 **)amd_topo_list; +} + + +/** + * void amd_ht_init(struct sys_info *sysinfo) + * + * AMD HT init LinuxBIOS wrapper + * + */ +void amd_ht_init(struct sys_info *sysinfo) +{ + AMD_HTBLOCK ht_wrapper = { + NULL, // u8 **topolist; + 0, // u8 AutoBusStart; + 32, // u8 AutoBusMax; + 6, // u8 AutoBusIncrement; + NULL, // BOOL (*AMD_CB_IgnoreLink)(); + NULL, // BOOL (*AMD_CB_OverrideBusNumbers)(); + NULL, // BOOL (*AMD_CB_ManualBUIDSwapList)(); + NULL, // void (*AMD_CB_DeviceCapOverride)(); + NULL, // void (*AMD_CB_Cpu2CpuPCBLimits)(); + NULL, // void (*AMD_CB_IOPCBLimits)(); + NULL, // BOOL (*AMD_CB_SkipRegang)(); + NULL, // BOOL (*AMD_CB_CustomizeTrafficDistribution)(); + NULL, // BOOL (*AMD_CB_CustomizeBuffers)(); + NULL, // void (*AMD_CB_OverrideDevicePort)(); + NULL, // void (*AMD_CB_OverrideCpuPort)(); + AMD_CB_EventNotify // void (*AMD_CB_EventNotify) (); + }; + + printk_debug("Enter amd_ht_init()\n"); + amdHtInitialize(&ht_wrapper); + printk_debug("Exit amd_ht_init()\n"); + + +} + + + + diff --git a/src/northbridge/amd/amdht/porting.h b/src/northbridge/amd/amdht/porting.h new file mode 100644 index 0000000000..534e742fd5 --- /dev/null +++ b/src/northbridge/amd/amdht/porting.h @@ -0,0 +1,88 @@ +/* + * This file is part of the LinuxBIOS 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 + */ + +#ifndef PORTING_H +#define PORTING_H + + +/* For AMD64 or 32-bit GCC */ +typedef int int32; +typedef unsigned int uint32; +typedef short int16; +typedef unsigned short uint16; +typedef char int8; +typedef unsigned char uint8; + +/* Create the Boolean type */ +#define TRUE 1 +#define FALSE 0 +typedef unsigned char BOOL; + +/* Force tight packing of structures */ +#pragma pack(1) + +#define CALLCONV + + +typedef struct _uint64 +{ + uint32 lo; + uint32 hi; +}uint64; + + +/* + * SBDFO - Segment Bus Device Function Offset + * 31:28 Segment (4-bits) + * 27:20 Bus (8-bits) + * 19:15 Device (5-bits) + * 14:12 Function(3-bits) + * 11:00 Offset (12-bits) + */ +typedef uint32 SBDFO; + +#define MAKE_SBDFO(seg,bus,dev,fun,off) ((((uint32)(seg))<<28) | (((uint32)(bus))<<20) | \ + (((uint32)(dev))<<15) | (((uint32)(fun))<<12) | ((uint32)(off))) +#define SBDFO_SEG(x) (((uint32)(x)>>28) & 0x0F) +#define SBDFO_BUS(x) (((uint32)(x)>>20) & 0xFF) +#define SBDFO_DEV(x) (((uint32)(x)>>15) & 0x1F) +#define SBDFO_FUN(x) (((uint32)(x)>>12) & 0x07) +#define SBDFO_OFF(x) (((uint32)(x)) & 0xFFF) +#define ILLEGAL_SBDFO 0xFFFFFFFF + +void CALLCONV AmdMSRRead(uint32 Address, uint64 *Value); +void CALLCONV AmdMSRWrite(uint32 Address, uint64 *Value); +void CALLCONV AmdIORead(uint8 IOSize, uint16 Address, uint32 *Value); +void CALLCONV AmdIOWrite(uint8 IOSize, uint16 Address, uint32 *Value); +void CALLCONV AmdMemRead(uint8 MemSize, uint64 *Address, uint32 *Value); +void CALLCONV AmdMemWrite(uint8 MemSize, uint64 *Address, uint32 *Value); +void CALLCONV AmdPCIRead(SBDFO loc, uint32 *Value); +void CALLCONV AmdPCIWrite(SBDFO loc, uint32 *Value); +void CALLCONV AmdCPUIDRead(uint32 Address, uint32 Regs[4]); +void CALLCONV ErrorStop(uint32 Value); + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define BYTESIZE 1 +#define WORDSIZE 2 +#define DWORDSIZE 4 + +#endif /* PORTING_H */ |