Am Dienstag, den 14.05.2013, 11:03 +0200 schrieb Paul Menzel:
Am Montag, den 13.05.2013, 09:04 +0200 schrieb Paul Menzel:
Am Sonntag, den 12.05.2013, 15:40 +0200 schrieb Peter Stuge:
Paul Menzel wrote:
do you know if the timer mentioned in the BIOS and Kernel Developer’s Guide (BKGD) for the AMD Family 14h processors [1]
2.11.4 BIOS Timer The root complex implements a 32-bit microsecond timer (see D0F0xE4_x0130_80F0 and D0F0xE4_x0130_80F1) that the BIOS can use to accurately time wait operations between initialization steps. To ensure that BIOS waits a minimum number of microseconds between steps BIOS should always wait for one microsecond more than the required minimum wait time.
could be used for implementing `tsc_freq_mhz()` as done for Intel Haswell processors?
Isn't that quite clear from the text that you quoted?
Probably, yes. As this area is new to me, I prefer to ask and get confirmation to be sure.
It looks like it is not the same. The BIOS Timer above is more to fit Aaron’s commit.
commit c46cc6f149c42653344d6e9f3656a4212fc46cef Author: Aaron Durbin <adurbin@chromium.org> Date: Mon Apr 29 16:57:10 2013 -0500 haswell: 24MHz monotonic time implementation Haswell ULT devices have a 24MHz package-level counter. Use this counter to provide a timer_monotonic_get() implementation. Reviewed-on: http://review.coreboot.org/3153
But the problem is, that the register is part of the PCI config space(?) and the Root Complex/PCI stuff is not yet available in ramstage?
+#include <stdint.h> +#include <pci_ops.h> +#include <timer.h> + +static struct monotonic_counter { + int initialized; + struct mono_time time; + uint32_t last_value; +} mono_counter; + +static inline uint32_t read_counter_msr(void) +{ + /* D0F0xE4_x0130_80F0 BIOS Timer + * + * This field increments once every microsecond when the timer is + * enabled. The counter rolls over and continues counting when it + * reaches FFFF_FFFFh. A write to this register causes the counter + * to reset and begin counting from the value written. */ + pci_write_config32(CI_DEV(0, 0, 0), 0xe4, 0x013080F0);
The above was supposed to be `PCI_DEV`. I had not squashed the commits yet.
+ + return pci_read_config32(PCI_DEV(0, 0, 0), 0xe4); +} + +void timer_monotonic_get(struct mono_time *mt) +{ + uint32_t current_tick; + uint32_t usecs_elapsed; + + if (!mono_counter.initialized) { + mono_counter.last_value = read_counter_msr(); + mono_counter.initialized = 1; + } + + current_tick = read_counter_msr(); + usecs_elapsed = current_tick - mono_counter.last_value; + + /* Update current time and tick values only if a full tick occurred. */ + if (usecs_elapsed) { + mono_time_add_usecs(&mono_counter.time, usecs_elapsed); + mono_counter.last_value = current_tick; + } + + /* Save result. */ + *mt = mono_counter.time; +}
This results in the following hang.
00.000: <00> 00.456: 00.456: 00.456: coreboot-4.0-4160-g41f456b-dirty Tue May 14 00:28:53 CEST 2013 starting... 00.456: BSP Family_Model: 00500f10 00.457: cpu_init_detectedx = 00000000 00.457: agesawrapper_amdinitmmio passed. 00.458: agesawrapper_amdinitreset passed. 00.461: agesawrapper_amdinitearly BSP Family_Model: 00500f10 00.486: cpu_init_detectedx = 00000001 00.486: agesawrapper_amdinitmmio passed. 00.487: agesawrapper_amdinitreset passed. 00.491: agesawrapper_amdinitearly passed. 00.627: agesawrapper_amdinitpost passed. 00.753: agesawrapper_amdinitenv passed. 00.767: Loading image. 00.768: CBFS: loading stage fallback/coreboot_ram @ 0x200000 (1343544 bytes), entry @ 0x200000 00.873: Jumping to image. 00.874: coreboot-4.0-4160-g41f456b-dirty Tue May 14 00:28:53 CEST 2013 booting... 00.874: get_pbus: dev is NULL!
In #coreboor, CareBear\ suggested that I have to access the PCI register in a different way. Suggestions very much welcomed.
Suggestions, if this should be shared and how the files should be named are appreciated.
Yes and no. We can do this for coreboot's own code for AMD platforms, but it obviously does not make much sense to hack this into AGESA if there are not already provisions for it.
I totally forgot about that. There is coreboot code for the K8 and Family 10h processors, if I am not mistaken.
AGESA is there for Family 10h to 15h processors.
Since AGESA is the only thing relevant going forward the question is what AGESA needs, timing-wise. Have you checked?
Only a little. Having an ASRock E350M1, I am looking into the Family 14h family. There seems to be no TSC stuff in `src/cpu/amd`. But the AMD vendor code seems to have it.
$ git grep -i tsc src/vendorcode/amd/agesa/f14/
`AGESA.h` has a struct `MEM_DATA_STRUCT` where the frequency is put into.
$ nl -ba src/vendorcode/amd/agesa/f14/AGESA.h | grep -B 40 -A 5 TSC […] 1700 /// 1701 /// Contains all data relevant to Memory Initialization. 1702 /// 1703 typedef struct _MEM_DATA_STRUCT { 1704 IN AMD_CONFIG_PARAMS StdHeader; ///< Standard configuration header 1705 1706 IN MEM_PARAMETER_STRUCT *ParameterListPtr; ///< List of input Parameters 1707 1708 OUT MEM_FUNCTION_STRUCT FunctionList; ///< List of function Pointers 1709 1710 IN OUT AGESA_STATUS (*GetPlatformCfg[MAX_PLATFORM_TYPES]) (struct _MEM_DATA_STRUCT *MemData, UINT8 SocketID, CH_DEF_STRUCT *CurrentChannel); ///< look-up platform info 1711 1712 IN OUT BOOLEAN (*ErrorHandling)(struct _DIE_STRUCT *MCTPtr, UINT8 DCT, UINT16 ChipSelMask, AMD_CONFIG_PARAMS *StdHeader); ///< Error Handling 1713 1714 1715 OUT MEM_SOCKET_STRUCT SocketList[MAX_SOCKETS_SUPPORTED]; ///< Socket list for memory code. 1716 ///< SocketList is a shortcut for IBVs to retrieve training 1717 ///< and timing data for each channel indexed by socket/channel, 1718 ///< eliminating their need to parse die/dct/channel etc. 1719 ///< It contains pointers to the populated data structures for 1720 ///< each channel and skips the channel structures that are 1721 ///< unpopulated. In the case of channels sharing the same DCT, 1722 ///< the pTimings pointers will point to the same DCT Timing data. 1723 1724 OUT DIE_STRUCT *DiesPerSystem; ///< Pointed to an array of DIE_STRUCTs 1725 OUT UINT8 DieCount; ///< Number of MCTs in the system. 1726 1727 IN SPD_DEF_STRUCT *SpdDataStructure; ///< Pointer to SPD Data structure 1728 1729 IN OUT struct _PLATFORM_CONFIGURATION *PlatFormConfig; ///< Platform profile/build option config structure 1730 1731 IN OUT BOOLEAN IsFlowControlSupported; ///< Indicates if flow control is supported 1732 1733 OUT UINT32 TscRate; ///< The rate at which the TSC increments in megahertz. 1734 1735 } MEM_DATA_STRUCT; […]
With
$ git grep -i tsc src/vendorcode/amd/agesa/f14/ | grep -i rate […] src/vendorcode/amd/agesa/f14/Proc/CPU/Family/0x14/cpuF14Utilities.c: * @CpuServiceMethod{::F_CPU_GET_TSC_RATE}. src/vendorcode/amd/agesa/f14/Proc/CPU/Family/0x14/cpuF14Utilities.c:F14GetTscRate ( src/vendorcode/amd/agesa/f14/Proc/CPU/Family/0x14/cpuF14Utilities.h:F14GetTscRate ( […]
I found `F14GetTscRate`.
$ nl -ba src/vendorcode/amd/agesa/f14/Proc/CPU/Family/0x14/cpuF14Utilities.c […] 213 /*---------------------------------------------------------------------------------------*/ 214 /** 215 * Determines the rate at which the executing core's time stamp counter is 216 * incrementing. 217 * 218 * @CpuServiceMethod{::F_CPU_GET_TSC_RATE}. 219 * 220 * @param[in] FamilySpecificServices The current Family Specific Services. 221 * @param[out] FrequencyInMHz TSC actual frequency. 222 * @param[in] StdHeader Header for library and services. 223 * 224 * @return The most severe status of all called services 225 */ 226 AGESA_STATUS 227 F14GetTscRate ( 228 IN CPU_SPECIFIC_SERVICES *FamilySpecificServices, 229 OUT UINT32 *FrequencyInMHz, 230 IN AMD_CONFIG_PARAMS *StdHeader 231 ) 232 { 233 UINT64 MsrReg; 234 PSTATE_CPU_FAMILY_SERVICES *FamilyServices; 235 236 FamilyServices = NULL; 237 GetFeatureServicesOfCurrentCore (&PstateFamilyServiceTable, (const VOID **)&FamilyServices, StdHeader); 238 ASSERT (FamilyServices != NULL); 239 240 LibAmdMsrRead (0xC0010015, &MsrReg, StdHeader); 241 if ((MsrReg & 0x01000000) != 0) { 242 return (FamilyServices->GetPstateFrequency (FamilyServices, 0, FrequencyInMHz, StdHeader)); 243 } else { 244 return (FamilySpecificServices->GetCurrentNbFrequency (FamilySpecificServices, FrequencyInMHz, StdHeader)); 245 } 246 } […]
So there is the infrastructure already. The only problem is how to hook this up into coreboot. Create `src/cpu/amd/agesa/tsc_delay.c` and somehow call the AGESA `F14GetTscRate()` from it?
There are also other timers in the processor cores.
2.4.5 Timers Each core includes the following timers. These timers do not vary in frequency regardless of the current P-state or C-state. • MSR0000_0010 [Time Stamp Counter (TSC)]; the TSC increments at the rate specified by MSRC001_0015[TscFreqSel]. • The APIC timer (APIC380 and APIC390), which decrements at a rate of 2x CLKIN.
It looks like that is what AGESA uses and which might be there from the “beginning”.
Thanks,
Paul