Jeremy Compostella dffb1c8933 cpu/x86/cache: Call wbinvd only once CR0.CD is set
This patch removes the wbinvd call preceding CR0.CD setting in
disable_cache() to improve the boot time performances. According to
some experimental measurements, the wbinvd execution takes between 1.6
up and 6 milliseconds to complete so it is preferable to call it only
when necessary.

According to Intel Software Developer Manual Vol 3.A - 12.5.3
Preventing Caching section there is no need to flush and invalidate
the cache before settings CR0.CD. The documented sequence consists in
setting CR0.CD and then call wbinvd.

We also could not find any extra requirements in the AMD64
Architecture Programmer’s Manual - Volume 2 - Memory System chapter.

This extra wbinvd in coreboot disable_cache() function does not seem
documented and looking into the history of the project got us all the
way back to original commit 8ca8d7665d67 ("- Initial checkin of the
freebios2 tree") from April 2003.

Even the original disable_cache() implementation (see below) is a bit
curious as the comment list two actions:
1. Disable cache cover by line 74, 75 and 77
2. Write back the cache and flush TLB - Line 78
But it does not provide any explanation for the wbinvd call line 76.

    68  static inline void disable_cache(void)
    69  {
    70          unsigned int tmp;
    71          /* Disable cache */
    72          /* Write back the cache and flush TLB */
    73          asm volatile (
    74                  "movl  %%cr0, %0\n\t"
    75                  "orl  $0x40000000, %0\n\t"
    76                  "wbinvd\n\t"
    77                  "movl  %0, %%cr0\n\t"
    78                  "wbinvd\n\t"
    79                  :"=r" (tmp)
    80                  ::"memory");
    81  }

BUG=b/260455826
TEST=Successful boot on Skolas and Rex board

Change-Id: I08c6486dc93c4d70cadc22a760d1b7e536e85bfa
Signed-off-by: Jeremy Compostella <jeremy.compostella@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/75474
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Subrata Banik <subratabanik@google.com>
Reviewed-by: Himanshu Sahdev <himanshu.sahdev@intel.com>
2023-06-01 07:52:03 +00:00

66 lines
1.5 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef CPU_X86_CACHE
#define CPU_X86_CACHE
#include <cpu/x86/cr.h>
#define CR0_CacheDisable (CR0_CD)
#define CR0_NoWriteThrough (CR0_NW)
#define CPUID_FEATURE_CLFLUSH_BIT 19
#if !defined(__ASSEMBLER__)
#include <stdbool.h>
#include <stddef.h>
static inline void wbinvd(void)
{
asm volatile ("wbinvd" ::: "memory");
}
static inline void invd(void)
{
asm volatile("invd" ::: "memory");
}
static inline void clflush(void *addr)
{
asm volatile ("clflush (%0)"::"r" (addr));
}
bool clflush_supported(void);
void clflush_region(const uintptr_t start, const size_t size);
/* The following functions require the __always_inline due to AMD
* function STOP_CAR_AND_CPU that disables cache as
* RAM, the cache as RAM stack can no longer be used. Called
* functions must be inlined to avoid stack usage. Also, the
* compiler must keep local variables register based and not
* allocated them from the stack. With gcc 4.5.0, some functions
* declared as inline are not being inlined. This patch forces
* these functions to always be inlined by adding the qualifier
* __always_inline to their declaration.
*/
static __always_inline void enable_cache(void)
{
CRx_TYPE cr0;
cr0 = read_cr0();
cr0 &= ~(CR0_CD | CR0_NW);
write_cr0(cr0);
}
static __always_inline void disable_cache(void)
{
/* Disable and write back the cache */
CRx_TYPE cr0;
cr0 = read_cr0();
cr0 |= CR0_CD;
write_cr0(cr0);
wbinvd();
}
#endif /* !__ASSEMBLER__ */
#endif /* CPU_X86_CACHE */