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 <[email protected]>
        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);
        +
        +       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!

> > > 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

Attachment: signature.asc
Description: This is a digitally signed message part

-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to