Hi Ray, Can you please help to review this patch again? Thanks, Chao On 2024/1/26 14:29, Chao Li wrote: > Add the LoongArch64 CPU Timer instance to CpuTimerLib, using CPUCFG 0x4 > and 0x5 for Stable Counter frequency. > > BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584 > > Cc: Eric Dong > Cc: Ray Ni > Cc: Rahul Kumar > Cc: Gerd Hoffmann > Signed-off-by: Chao Li > --- > .../Library/CpuTimerLib/BaseCpuTimerLib.inf | 9 +- > .../CpuTimerLib/LoongArch64/CpuTimerLib.c | 251 ++++++++++++++++++ > 2 files changed, 258 insertions(+), 2 deletions(-) > create mode 100644 UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c > > diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf > index de0648de91..7e6152ef7e 100644 > --- a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf > +++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf > @@ -5,6 +5,7 @@ > # counter features are provided by the processors time stamp counter. > # > # Copyright (c) 2021, Intel Corporation. All rights reserved.
> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > @@ -18,18 +19,22 @@ > LIBRARY_CLASS = TimerLib > MODULE_UNI_FILE = BaseCpuTimerLib.uni > > -[Sources] > +[Sources.IA32, Sources.X64] > CpuTimerLib.c > BaseCpuTimerLib.c > > +[Sources.LOONGARCH64] > + LoongArch64/CpuTimerLib.c > + > [Packages] > MdePkg/MdePkg.dec > UefiCpuPkg/UefiCpuPkg.dec > > [LibraryClasses] > BaseLib > - PcdLib > DebugLib > + PcdLib > + SafeIntLib > > [Pcd] > gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES > diff --git a/UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c > new file mode 100644 > index 0000000000..a5ae8d0185 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c > @@ -0,0 +1,251 @@ > +/** @file > + CPUCFG 0x4 and 0x5 for Stable Counter frequency instance of Timer Library. > + > + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +/** > + Calculate clock frequency using CPUCFG 0x4 and 0x5 registers. > + > + @param VOID. > + > + @return The frequency in Hz. > + > +**/ > +STATIC > +UINT64 > +CalcConstFreq ( > + VOID > + ) > +{ > + UINT32 BaseFreq; > + UINT64 ClockMultiplier; > + UINT32 ClockDivide; > + CPUCFG_REG4_INFO_DATA CcFreq; > + CPUCFG_REG5_INFO_DATA CpucfgReg5Data; > + UINT64 StableTimerFreq; > + > + // > + // Get the the crystal frequency corresponding to the constant > + // frequency timer and the clock used by the timer. > + // > + AsmCpucfg (CPUCFG_REG4_INFO, &CcFreq.Uint32); > + > + // > + // Get the multiplication factor and frequency division factor > + // corresponding to the constant frequency timer and the clock > + // used by the timer. > + // > + AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32); > + > + BaseFreq = CcFreq.Bits.CC_FREQ; > + ClockMultiplier = CpucfgReg5Data.Bits.CC_MUL & 0xFFFF; > + ClockDivide = CpucfgReg5Data.Bits.CC_DIV & 0xFFFF; > + > + if ((BaseFreq == 0x0) || (ClockMultiplier == 0x0) || (ClockDivide == 0x0)) { > + DEBUG (( > + DEBUG_ERROR, > + "LoongArch Stable Timer is not available in the CPU, hence this library cannot be used.\n" > + )); > + ASSERT (FALSE); > + CpuDeadLoop (); > + } > + > + StableTimerFreq = ((ClockMultiplier * BaseFreq) / ClockDivide); > + > + if (StableTimerFreq == 0x0) { > + ASSERT (FALSE); > + } > + > + return StableTimerFreq; > +} > + > +/** > + Stalls the CPU for at least the given number of microseconds. > + > + Stalls the CPU for the number of microseconds specified by MicroSeconds. > + > + @param MicroSeconds The minimum number of microseconds to delay. > + > + @return MicroSeconds > + > +**/ > +UINTN > +EFIAPI > +MicroSecondDelay ( > + IN UINTN MicroSeconds > + ) > +{ > + UINT64 CurrentTicks, ExceptedTicks, Remaining; > + RETURN_STATUS Status; > + > + Status = SafeUint64Mult (MicroSeconds, CalcConstFreq (), &Remaining); > + ASSERT_RETURN_ERROR (Status); > + > + ExceptedTicks = DivU64x32 (Remaining, 1000000U); > + CurrentTicks = AsmReadStableCounter (); > + ExceptedTicks += CurrentTicks; > + > + do { > + CurrentTicks = AsmReadStableCounter (); > + } while (CurrentTicks < ExceptedTicks); > + > + return MicroSeconds; > +} > + > +/** > + Stalls the CPU for at least the given number of nanoseconds. > + > + Stalls the CPU for the number of nanoseconds specified by NanoSeconds. > + > + @param NanoSeconds The minimum number of nanoseconds to delay. > + > + @return NanoSeconds > + > +**/ > +UINTN > +EFIAPI > +NanoSecondDelay ( > + IN UINTN NanoSeconds > + ) > +{ > + UINTN MicroSeconds; > + > + // Round up to 1us Tick Number > + MicroSeconds = NanoSeconds / 1000; > + MicroSeconds += ((NanoSeconds % 1000) == 0) ? 0 : 1; > + > + MicroSecondDelay (MicroSeconds); > + > + return NanoSeconds; > +} > + > +/** > + Retrieves the current value of a 64-bit free running Stable Counter. > + > + The LoongArch defines a constant frequency timer, whose main body is a > + 64-bit counter called StableCounter. StableCounter is set to 0 after > + reset, and then increments by 1 every counting clock cycle. When the > + count reaches all 1s, it automatically wraps around to 0 and continues > + to increment. > + The properties of the Stable Counter can be retrieved from > + GetPerformanceCounterProperties(). > + > + @return The current value of the Stable Counter. > + > +**/ > +UINT64 > +EFIAPI > +GetPerformanceCounter ( > + VOID > + ) > +{ > + // > + // Just return the value of Stable Counter. > + // > + return AsmReadStableCounter (); > +} > + > +/** > + Retrieves the 64-bit frequency in Hz and the range of Stable Counter > + values. > + > + If StartValue is not NULL, then the value that the stbale counter starts > + with immediately after is it rolls over is returned in StartValue. If > + EndValue is not NULL, then the value that the stable counter end with > + immediately before it rolls over is returned in EndValue. The 64-bit > + frequency of the system frequency in Hz is always returned. > + > + @param StartValue The value the stable counter starts with when it > + rolls over. > + @param EndValue The value that the stable counter ends with before > + it rolls over. > + > + @return The frequency in Hz. > + > +**/ > +UINT64 > +EFIAPI > +GetPerformanceCounterProperties ( > + OUT UINT64 *StartValue OPTIONAL, > + OUT UINT64 *EndValue OPTIONAL > + ) > +{ > + if (StartValue != NULL) { > + *StartValue = 0; > + } > + > + if (EndValue != NULL) { > + *EndValue = 0xFFFFFFFFFFFFFFFFULL; > + } > + > + return CalcConstFreq (); > +} > + > +/** > + Converts elapsed ticks of performance counter to time in nanoseconds. > + > + This function converts the elapsed ticks of running performance counter to > + time value in unit of nanoseconds. > + > + @param Ticks The number of elapsed ticks of running performance counter. > + > + @return The elapsed time in nanoseconds. > + > +**/ > +UINT64 > +EFIAPI > +GetTimeInNanoSecond ( > + IN UINT64 Ticks > + ) > +{ > + UINT64 Frequency; > + UINT64 NanoSeconds; > + UINT64 Remainder; > + INTN Shift; > + RETURN_STATUS Status; > + > + Frequency = GetPerformanceCounterProperties (NULL, NULL); > + > + // > + // Ticks > + // Time = --------- x 1,000,000,000 > + // Frequency > + // > + Status = SafeUint64Mult ( > + DivU64x64Remainder (Ticks, Frequency, &Remainder), > + 1000000000u, > + &NanoSeconds > + ); > + > + // > + // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit. > + // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34, > + // i.e. highest bit set in Remainder should <= 33. > + // > + Shift = MAX (0, HighBitSet64 (Remainder) - 33); > + Remainder = RShiftU64 (Remainder, (UINTN)Shift); > + Frequency = RShiftU64 (Frequency, (UINTN)Shift); > + > + Status = SafeUint64Add ( > + NanoSeconds, > + DivU64x64Remainder ( > + MultU64x32 (Remainder, 1000000000u), > + Frequency, > + NULL > + ), > + &NanoSeconds > + ); > + ASSERT_RETURN_ERROR (Status); > + > + return NanoSeconds; > +} -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114848): https://edk2.groups.io/g/devel/message/114848 Mute This Topic: https://groups.io/mt/104068936/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-