367 lines
7.8 KiB
C
367 lines
7.8 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* common/cmd_testsmpcache.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <linux/compiler.h>
|
|
#include <asm/arch/cpu.h>
|
|
#include <asm/arch/core.h>
|
|
#include <asm/arch/timer.h>
|
|
#include <linux/arm-smccc.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#define CPU_ON 1
|
|
#define CPU_OFF 0
|
|
#define STACK_SIZE 4096
|
|
|
|
typedef void (*test_pattern_t)(unsigned int *memstart, unsigned int count);
|
|
|
|
unsigned long core_stack[NR_CPUS][STACK_SIZE/8] __attribute__ ((aligned (16)));
|
|
unsigned core_online[NR_CPUS];
|
|
unsigned long core_entry_fn[NR_CPUS];
|
|
unsigned long gd_addr;
|
|
unsigned int val;
|
|
|
|
void test_cache_pattern1(unsigned int *memstart, unsigned int count)
|
|
{
|
|
unsigned long i;
|
|
unsigned int *addr;
|
|
unsigned long size;
|
|
int ret;
|
|
int process;
|
|
int errcnt;
|
|
|
|
printf("test cache pattern1 -- : ");
|
|
flush_dcache_all();
|
|
|
|
addr = memstart;
|
|
size = count/sizeof(unsigned);
|
|
for (i=0; i<size; i++, addr++)
|
|
*addr = (0xffffffff ^ ((unsigned)(unsigned long)addr));
|
|
flush_dcache_all();
|
|
|
|
addr = memstart;
|
|
size = count/sizeof(unsigned);
|
|
for (i=0; i<size; i++, addr++)
|
|
val = *addr;
|
|
|
|
addr=memstart;
|
|
size = count/sizeof(unsigned);
|
|
ret = 0;
|
|
process = -1;
|
|
for (i=0, errcnt=0; i<size && errcnt<10; i++, addr++) {
|
|
if (*addr != (0xffffffff ^ ((unsigned)(unsigned long)addr))) {
|
|
printf("\n fail at: addr=0x%x,cache=0x%x,val=0x%x",
|
|
(unsigned)(unsigned long)addr,
|
|
*addr, (0xffffffff^((unsigned)(unsigned long)addr)));
|
|
errcnt++;
|
|
ret = 1;
|
|
}
|
|
else {
|
|
if (!ret && (((i*100)/(size)) != process)) {
|
|
process = ((i*100)/(size));
|
|
printf("\b\b\b%2d%%", process);
|
|
}
|
|
}
|
|
}
|
|
if (ret == 0)
|
|
printf("\b\b\b done!");
|
|
|
|
if (ret == 0)
|
|
printf("\ntest cache pattern1 result: success!\n");
|
|
else
|
|
printf("\ntest cache pattern1 result: fail!\n");
|
|
}
|
|
|
|
void test_cache_pattern2(unsigned int *memstart, unsigned int count)
|
|
{
|
|
unsigned long i;
|
|
unsigned int *addr;
|
|
unsigned long size;
|
|
int process;
|
|
int ret;
|
|
int errcnt;
|
|
|
|
printf("test cache pattern2 -- : ");
|
|
flush_dcache_all();
|
|
|
|
addr = memstart;
|
|
size = count/sizeof(unsigned);
|
|
for (i=0; i<size; i++, addr++)
|
|
*addr = 0x55555555;
|
|
flush_dcache_all();
|
|
|
|
addr = memstart;
|
|
size = count/sizeof(unsigned);
|
|
for (i=0; i<size; i++, addr++)
|
|
val = *addr;
|
|
|
|
// compare nocache and memorys
|
|
addr=memstart;
|
|
size = count/sizeof(unsigned);
|
|
ret = 0;
|
|
process = -1;
|
|
for (i=0, errcnt = 0; i<size && errcnt < 10; i++, addr++) {
|
|
if (*addr != 0x55555555) {
|
|
printf("\n fail at: addr=0x%x,cache=0x%x,val=0x%x",
|
|
(unsigned)(unsigned long)addr,
|
|
*addr, 0x55555555);
|
|
errcnt++;
|
|
ret = 1;
|
|
}
|
|
else {
|
|
if (!ret && (((i*100)/(size)) != process)) {
|
|
process = ((i*100)/(size));
|
|
printf("\b\b\b%2d%%", process);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ret == 0)
|
|
printf("\b\b\b done!");
|
|
|
|
if (ret == 0)
|
|
printf("\ntest cache pattern2 result: success!\n");
|
|
else
|
|
printf("\ntest cache pattern2 result: fail!\n");
|
|
}
|
|
|
|
void test_cache_pattern3(unsigned int *memstart, unsigned int count)
|
|
{
|
|
unsigned long i;
|
|
unsigned int *addr;
|
|
unsigned long size;
|
|
int process;
|
|
int ret;
|
|
int errcnt;
|
|
|
|
printf("test cache pattern3 -- : ");
|
|
flush_dcache_all();
|
|
|
|
addr = memstart;
|
|
size = count/sizeof(unsigned);
|
|
for (i=0; i<size; i++, addr++)
|
|
*addr = 0xaaaaaaaa;
|
|
flush_dcache_all();
|
|
|
|
addr = memstart;
|
|
size = count/sizeof(unsigned);
|
|
for (i=0; i<size; i++, addr++)
|
|
val = *addr;
|
|
|
|
// compare nocache and memorys
|
|
addr=memstart;
|
|
size = count/sizeof(unsigned);
|
|
ret = 0;
|
|
process = -1;
|
|
for (i=0, errcnt=0; i<size && errcnt < 10; i++, addr++) {
|
|
if (*addr != 0xaaaaaaaa) {
|
|
printf("\n fail at: addr=0x%x,cache=0x%x,val=0x%x",
|
|
(unsigned)(unsigned long)addr,
|
|
*addr, 0xaaaaaaaa);
|
|
errcnt++;
|
|
ret = 1;
|
|
}
|
|
else {
|
|
if (!ret && (((i*100)/(size)) != process)) {
|
|
process = ((i*100)/(size));
|
|
printf("\b\b\b%2d%%", process);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ret == 0)
|
|
printf("\b\b\b done!");
|
|
|
|
if (ret == 0)
|
|
printf("\ntest cache pattern3 result: success!\n");
|
|
else
|
|
printf("\ntest cache pattern3 result: fail!\n");
|
|
}
|
|
|
|
const test_pattern_t test_cache_pattern[] = {
|
|
test_cache_pattern1,
|
|
test_cache_pattern2,
|
|
test_cache_pattern3,
|
|
};
|
|
|
|
void test_cache(int cpuidx)
|
|
{
|
|
/*DRAM_END-128M --- RAM_END*/
|
|
unsigned int *memstart;
|
|
unsigned int count;
|
|
int i;
|
|
bd_t *bd = gd->bd;
|
|
|
|
memstart = (unsigned int *)(bd->bi_dram[0].start + bd->bi_dram[0].size);
|
|
count = CONFIG_SYS_MEM_TOP_HIDE;
|
|
|
|
printf("\n===========cpu%d test start: offset: 0x%x, count: %x\n",
|
|
cpuidx, (unsigned)(unsigned long)memstart, count);
|
|
for (i=0; i<sizeof(test_cache_pattern)/sizeof(test_pattern_t); i++) {
|
|
test_cache_pattern[i](memstart, count);
|
|
}
|
|
|
|
memset(memstart, 0, count);
|
|
flush_dcache_all();
|
|
}
|
|
|
|
unsigned get_gd_addr(void)
|
|
{
|
|
return gd_addr;
|
|
}
|
|
|
|
unsigned get_stack_base(unsigned cpuidx)
|
|
{
|
|
return (unsigned)((unsigned long)&(core_stack[cpuidx]) + STACK_SIZE);
|
|
}
|
|
|
|
unsigned long get_core_entry_fn(unsigned cpuidx)
|
|
{
|
|
return core_entry_fn[cpuidx];
|
|
}
|
|
|
|
void invoke_psci_fn(unsigned fn, unsigned targetcpu, unsigned entry_point, unsigned arg)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
arm_smccc_smc(fn, targetcpu, entry_point, arg, 0, 0, 0, 0, &res);
|
|
}
|
|
|
|
void power_off_secondary_cpu(int cpuidx)
|
|
{
|
|
core_online[cpuidx] = CPU_OFF;
|
|
__asm__ volatile("sev");
|
|
invoke_psci_fn(0x84000002, 0x0010000, 0, 0);
|
|
}
|
|
|
|
void secondary_cpu_test_cache_entry(int cpuidx)
|
|
{
|
|
test_cache(cpuidx);
|
|
power_off_secondary_cpu(cpuidx);
|
|
}
|
|
|
|
void secondary_cpu_test_smp_entry(int cpuidx)
|
|
{
|
|
printf("CPU%d power on!\n", cpuidx);
|
|
power_off_secondary_cpu(cpuidx);
|
|
}
|
|
|
|
extern void _start(void);
|
|
static int do_testcache(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
int i;
|
|
int test_cpus = 0;
|
|
int cpuid;
|
|
char *cpuarg = argv[1];
|
|
int mpidr, cpuidx;
|
|
|
|
if (argc > 2) {
|
|
printf("usage: testsmpcache cpu-[0~7|a]\n");
|
|
return 0;
|
|
}
|
|
if (strlen(argv[1]) != 5) {
|
|
printf("usage: testsmpcache cpu-[0~7|a]\n");
|
|
return 0;
|
|
}
|
|
|
|
cpuarg += 4;
|
|
switch (*cpuarg) {
|
|
case '0' ... '7':
|
|
cpuid = *cpuarg - '0';
|
|
if (cpuid >= get_core_max()) {
|
|
printf("usage: testsmpcache cpu-[0~7|a]\n");
|
|
return 0;
|
|
}
|
|
test_cpus |= (1 << cpuid);
|
|
break;
|
|
case 'a':
|
|
for (i = 0; i < get_core_max(); i++)
|
|
test_cpus |= (1 << i);
|
|
break;
|
|
default:
|
|
printf("usage: testsmpcache cpu-[0~7|a]\n");
|
|
return 0;
|
|
}
|
|
|
|
gd_addr = (unsigned long)gd;
|
|
flush_dcache_all();
|
|
|
|
if ((test_cpus & 0x1) == 0x1)
|
|
test_cache(0);
|
|
for (i = 1; i < get_core_max(); i++) {
|
|
if ((test_cpus & (1<<i)) != 0) {
|
|
mpidr = get_core_mpidr(i);
|
|
if (mpidr < 0) {
|
|
printf("cpu %d mpidr 0x%x error!\n", i, (unsigned int)mpidr);
|
|
return 0;
|
|
}
|
|
cpuidx = get_core_idx((unsigned int)mpidr);
|
|
if (cpuidx < 0) {
|
|
printf("cpu %d idx error!\n", i);
|
|
return 0;
|
|
}
|
|
|
|
core_online[cpuidx] = CPU_ON;
|
|
core_entry_fn[cpuidx] = (unsigned long)secondary_cpu_test_cache_entry;
|
|
__asm__ volatile("dsb sy");
|
|
invoke_psci_fn(0xC4000003, mpidr, (unsigned)(unsigned long)_start, 0);
|
|
while (core_online[cpuidx] == CPU_ON) {
|
|
__asm__ volatile("wfe");
|
|
__asm__ volatile("" : : : "memory");
|
|
}
|
|
_udelay(100);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_testsmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
int i;
|
|
int mpidr, cpuidx;
|
|
|
|
gd_addr = (unsigned long)gd;
|
|
flush_dcache_all();
|
|
|
|
for (i = 1; i < get_core_max(); i++) {
|
|
mpidr = get_core_mpidr(i);
|
|
if (mpidr < 0)
|
|
return -1;
|
|
cpuidx = get_core_idx((unsigned int)mpidr);
|
|
if (cpuidx < 0)
|
|
return -1;
|
|
core_online[cpuidx] = CPU_ON;
|
|
core_entry_fn[cpuidx] = (unsigned long)secondary_cpu_test_smp_entry;
|
|
__asm__ volatile("dsb sy");
|
|
invoke_psci_fn(0xC4000003, mpidr, (unsigned)(unsigned long)_start, 0);
|
|
while (core_online[cpuidx] == CPU_ON) {
|
|
__asm__ volatile("wfe");
|
|
__asm__ volatile("" : : : "memory");
|
|
}
|
|
_udelay(100);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_CMD(
|
|
testsmp, 1, 1, do_testsmp,
|
|
"test each CPU power on/off",
|
|
""
|
|
""
|
|
);
|
|
|
|
|
|
U_BOOT_CMD(
|
|
testcache, 2, 1, do_testcache,
|
|
"cache test",
|
|
"testcache cpu-[0-7|a]\n"
|
|
);
|