mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2026-08-08 12:08:03 -05:00
* loongarch: adjust 2K/3B6000M DDR rate factor * loongarch: Supports fewer cache layers than L3 For example: 2K2000 chip does not have L3, but has L2. If L2Cache is not flushed to memory, it will cause read and write data errors after cache_off.
153 lines
3.8 KiB
C
153 lines
3.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#ifndef CACHE_H
|
|
#define CACHE_H
|
|
/**
|
|
* \file
|
|
*
|
|
* Provides functions to enable, disable, and flush the CPU caches.
|
|
*
|
|
*//*
|
|
* Copyright (C) 2020-2022 Martin Whitaker.
|
|
*/
|
|
|
|
#ifdef __loongarch_lp64
|
|
#include <larchintrin.h>
|
|
#include "string.h"
|
|
#define cache_op(op,addr) \
|
|
__asm__ __volatile__( \
|
|
"cacop %0, %1\n" \
|
|
: \
|
|
: "i" (op), "ZC" (*(unsigned char *)(addr)))
|
|
static inline void cache_flush(void);
|
|
#endif
|
|
|
|
/**
|
|
* Disable the CPU caches.
|
|
*/
|
|
static inline void cache_off(void)
|
|
{
|
|
#if defined(__x86_64__)
|
|
__asm__ __volatile__ ("\t"
|
|
"movq %%cr0, %%rax \n\t"
|
|
"orl $0x40000000, %%eax \n\t" /* Set CD */
|
|
"movq %%rax, %%cr0 \n\t"
|
|
"wbinvd \n"
|
|
: /* no outputs */
|
|
: /* no inputs */
|
|
: "rax", "memory"
|
|
);
|
|
#elif defined(__i386__)
|
|
__asm__ __volatile__ ("\t"
|
|
"movl %%cr0, %%eax \n\t"
|
|
"orl $0x40000000, %%eax \n\t" /* Set CD */
|
|
"movl %%eax, %%cr0 \n\t"
|
|
"wbinvd \n"
|
|
: /* no outputs */
|
|
: /* no inputs */
|
|
: "eax", "memory"
|
|
);
|
|
#elif defined(__loongarch_lp64)
|
|
cache_flush();
|
|
__csrxchg_d(0, 3 << 4, 0x181);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Enable the CPU caches.
|
|
*/
|
|
static inline void cache_on(void)
|
|
{
|
|
#if defined(__x86_64__)
|
|
__asm__ __volatile__ ("\t"
|
|
"movq %%cr0, %%rax \n\t"
|
|
"andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */
|
|
"movq %%rax, %%cr0 \n"
|
|
: /* no outputs */
|
|
: /* no inputs */
|
|
: "rax", "memory"
|
|
);
|
|
#elif defined(__i386__)
|
|
__asm__ __volatile__ ("\t"
|
|
"movl %%cr0, %%eax \n\t"
|
|
"andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */
|
|
"movl %%eax, %%cr0 \n"
|
|
: /* no outputs */
|
|
: /* no inputs */
|
|
: "eax", "memory"
|
|
);
|
|
#elif defined(__loongarch_lp64)
|
|
cache_flush();
|
|
__csrxchg_d(1 << 4, 3 << 4, 0x181);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Flush the CPU caches.
|
|
*/
|
|
static inline void cache_flush(void)
|
|
{
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
__asm__ __volatile__ ("\t"
|
|
"wbinvd\n"
|
|
: /* no outputs */
|
|
: /* no inputs */
|
|
: "memory"
|
|
);
|
|
#elif defined (__loongarch_lp64)
|
|
uint64_t cache_present, cache_info_reg;
|
|
/*detect_max_cache_level*/
|
|
if (__cpucfg(0x10) & (1 << 10)) {
|
|
cache_present = 3; //L3 unified cache
|
|
} else if (__cpucfg(0x10) & (1 << 3)) {
|
|
cache_present = 2; //L2 unified cache
|
|
} else if (__cpucfg(0x10) & (1 << 0)) {
|
|
cache_present = 1; //L1 data cache
|
|
} else {
|
|
return; //No Cache present
|
|
}
|
|
cache_info_reg = 0x11 + cache_present; //cache last leaf
|
|
|
|
uint64_t ways = (__cpucfg(cache_info_reg) & 0xFFFF) + 1;
|
|
uint64_t sets = 1 << ((__cpucfg(cache_info_reg) >> 16) & 0xFF);
|
|
uint64_t line_size = 1 << ((__cpucfg(cache_info_reg) >> 24) & 0x7F);
|
|
uint64_t va, i, j;
|
|
uint64_t cpu_module[1];
|
|
va = 0;
|
|
|
|
cpu_module[0] = (uint64_t)__iocsrrd_d(0x20);
|
|
if (strstr((const char *)cpu_module, "3A6000")) {
|
|
uint8_t old_sc_cfg;
|
|
old_sc_cfg = __iocsrrd_b(0x280);
|
|
__iocsrwr_b(0x1, 0x280);
|
|
for (i = 0; i < (ways * 3); i++) {
|
|
for (j = 0; j < sets; j++) {
|
|
*(volatile uint32_t *)va;
|
|
va += line_size;
|
|
}
|
|
}
|
|
__iocsrwr_b(old_sc_cfg, 0x280);
|
|
} else {
|
|
for (i = 0; i < sets; i++) {
|
|
for (j = 0; j < ways; j++) {
|
|
switch (cache_present) {
|
|
case 1:
|
|
cache_op(0x9,va); //Flush L1
|
|
break;
|
|
case 2:
|
|
cache_op(0xA,va); //Flush L2
|
|
break;
|
|
case 3:
|
|
cache_op(0xB,va); //Flush L3
|
|
break;
|
|
}
|
|
va++;
|
|
}
|
|
va -= ways;
|
|
va += line_size;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif // CACHE_H
|