1bec58c1cSLevente Kurusa /* 2bec58c1cSLevente Kurusa * PSCI tests 3bec58c1cSLevente Kurusa * 4bec58c1cSLevente Kurusa * Copyright (C) 2017, Red Hat, Inc. 5bec58c1cSLevente Kurusa * Author: Levente Kurusa <lkurusa@redhat.com> 6bec58c1cSLevente Kurusa * Author: Andrew Jones <drjones@redhat.com> 7bec58c1cSLevente Kurusa * 8bec58c1cSLevente Kurusa * This work is licensed under the terms of the GNU LGPL, version 2. 9bec58c1cSLevente Kurusa */ 10bec58c1cSLevente Kurusa #include <libcflat.h> 11f082e37fSAndrew Jones #include <errata.h> 12bbf5c84bSAndrew Jones #include <asm/processor.h> 13bec58c1cSLevente Kurusa #include <asm/smp.h> 14bec58c1cSLevente Kurusa #include <asm/psci.h> 15bec58c1cSLevente Kurusa 16bbf5c84bSAndrew Jones static bool invalid_function_exception; 17bbf5c84bSAndrew Jones 18bbf5c84bSAndrew Jones #ifdef __arm__ 19bbf5c84bSAndrew Jones static void invalid_function_handler(struct pt_regs *regs __unused) 20bbf5c84bSAndrew Jones { 21bbf5c84bSAndrew Jones invalid_function_exception = true; 22bbf5c84bSAndrew Jones } 23bbf5c84bSAndrew Jones #else 24bbf5c84bSAndrew Jones static void invalid_function_handler(struct pt_regs *regs, unsigned int esr __unused) 25bbf5c84bSAndrew Jones { 26bbf5c84bSAndrew Jones invalid_function_exception = true; 27bbf5c84bSAndrew Jones regs->pc += 4; 28bbf5c84bSAndrew Jones } 29bbf5c84bSAndrew Jones #endif 30bbf5c84bSAndrew Jones 31bbf5c84bSAndrew Jones static void install_invalid_function_handler(exception_fn handler) 32bbf5c84bSAndrew Jones { 33bbf5c84bSAndrew Jones #ifdef __arm__ 34bbf5c84bSAndrew Jones install_exception_handler(EXCPTN_UND, handler); 35bbf5c84bSAndrew Jones #else 36bbf5c84bSAndrew Jones install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, handler); 37bbf5c84bSAndrew Jones #endif 38bbf5c84bSAndrew Jones } 39bbf5c84bSAndrew Jones 40bec58c1cSLevente Kurusa static bool psci_invalid_function(void) 41bec58c1cSLevente Kurusa { 42bbf5c84bSAndrew Jones bool pass; 43bbf5c84bSAndrew Jones 44bbf5c84bSAndrew Jones install_invalid_function_handler(invalid_function_handler); 45bbf5c84bSAndrew Jones 46bbf5c84bSAndrew Jones pass = psci_invoke(1337, 0, 0, 0) == PSCI_RET_NOT_SUPPORTED || invalid_function_exception; 47bbf5c84bSAndrew Jones 48bbf5c84bSAndrew Jones install_invalid_function_handler(NULL); 49bbf5c84bSAndrew Jones return pass; 50bec58c1cSLevente Kurusa } 51bec58c1cSLevente Kurusa 52bec58c1cSLevente Kurusa static int psci_affinity_info(unsigned long target_affinity, uint32_t lowest_affinity_level) 53bec58c1cSLevente Kurusa { 54bec58c1cSLevente Kurusa #ifdef __arm__ 55bec58c1cSLevente Kurusa return psci_invoke(PSCI_0_2_FN_AFFINITY_INFO, target_affinity, lowest_affinity_level, 0); 56bec58c1cSLevente Kurusa #else 57bec58c1cSLevente Kurusa return psci_invoke(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level, 0); 58bec58c1cSLevente Kurusa #endif 59bec58c1cSLevente Kurusa } 60bec58c1cSLevente Kurusa 61bec58c1cSLevente Kurusa static bool psci_affinity_info_on(void) 62bec58c1cSLevente Kurusa { 63bec58c1cSLevente Kurusa return psci_affinity_info(cpus[0], 0) == PSCI_0_2_AFFINITY_LEVEL_ON; 64bec58c1cSLevente Kurusa } 65bec58c1cSLevente Kurusa 66bec58c1cSLevente Kurusa static bool psci_affinity_info_off(void) 67bec58c1cSLevente Kurusa { 68bec58c1cSLevente Kurusa return psci_affinity_info(cpus[1], 0) == PSCI_0_2_AFFINITY_LEVEL_OFF; 69bec58c1cSLevente Kurusa } 70bec58c1cSLevente Kurusa 71bec58c1cSLevente Kurusa static int cpu_on_ret[NR_CPUS]; 72bec58c1cSLevente Kurusa static cpumask_t cpu_on_ready, cpu_on_done; 73bec58c1cSLevente Kurusa static volatile int cpu_on_start; 74bec58c1cSLevente Kurusa 75bec58c1cSLevente Kurusa static void cpu_on_secondary_entry(void) 76bec58c1cSLevente Kurusa { 77bec58c1cSLevente Kurusa int cpu = smp_processor_id(); 78bec58c1cSLevente Kurusa 79bec58c1cSLevente Kurusa cpumask_set_cpu(cpu, &cpu_on_ready); 80bec58c1cSLevente Kurusa while (!cpu_on_start) 81bec58c1cSLevente Kurusa cpu_relax(); 82e14e6ba5SAlexandru Elisei cpu_on_ret[cpu] = psci_cpu_on(cpus[1], __pa(halt)); 83bec58c1cSLevente Kurusa cpumask_set_cpu(cpu, &cpu_on_done); 84bec58c1cSLevente Kurusa } 85bec58c1cSLevente Kurusa 86bec58c1cSLevente Kurusa static bool psci_cpu_on_test(void) 87bec58c1cSLevente Kurusa { 88bec58c1cSLevente Kurusa bool failed = false; 89e14e6ba5SAlexandru Elisei int ret_success = 0; 90bec58c1cSLevente Kurusa int cpu; 91bec58c1cSLevente Kurusa 92bec58c1cSLevente Kurusa cpumask_set_cpu(1, &cpu_on_ready); 93bec58c1cSLevente Kurusa cpumask_set_cpu(1, &cpu_on_done); 94bec58c1cSLevente Kurusa 95bec58c1cSLevente Kurusa for_each_present_cpu(cpu) { 96bec58c1cSLevente Kurusa if (cpu < 2) 97bec58c1cSLevente Kurusa continue; 98bec58c1cSLevente Kurusa smp_boot_secondary(cpu, cpu_on_secondary_entry); 99bec58c1cSLevente Kurusa } 100bec58c1cSLevente Kurusa 101bec58c1cSLevente Kurusa cpumask_set_cpu(0, &cpu_on_ready); 102bec58c1cSLevente Kurusa while (!cpumask_full(&cpu_on_ready)) 103bec58c1cSLevente Kurusa cpu_relax(); 104bec58c1cSLevente Kurusa 105bec58c1cSLevente Kurusa cpu_on_start = 1; 106bec58c1cSLevente Kurusa smp_mb(); 107bec58c1cSLevente Kurusa 108e14e6ba5SAlexandru Elisei cpu_on_ret[0] = psci_cpu_on(cpus[1], __pa(halt)); 109bec58c1cSLevente Kurusa cpumask_set_cpu(0, &cpu_on_done); 110bec58c1cSLevente Kurusa 111bec58c1cSLevente Kurusa while (!cpumask_full(&cpu_on_done)) 112bec58c1cSLevente Kurusa cpu_relax(); 113bec58c1cSLevente Kurusa 114bec58c1cSLevente Kurusa for_each_present_cpu(cpu) { 115bec58c1cSLevente Kurusa if (cpu == 1) 116bec58c1cSLevente Kurusa continue; 117e14e6ba5SAlexandru Elisei if (cpu_on_ret[cpu] == PSCI_RET_SUCCESS) { 118e14e6ba5SAlexandru Elisei ret_success++; 119e14e6ba5SAlexandru Elisei } else if (cpu_on_ret[cpu] != PSCI_RET_ALREADY_ON) { 120bec58c1cSLevente Kurusa report_info("unexpected cpu_on return value: caller=CPU%d, ret=%d", cpu, cpu_on_ret[cpu]); 121bec58c1cSLevente Kurusa failed = true; 122bec58c1cSLevente Kurusa } 123bec58c1cSLevente Kurusa } 124bec58c1cSLevente Kurusa 125e14e6ba5SAlexandru Elisei if (ret_success != 1) { 126e14e6ba5SAlexandru Elisei report_info("got %d CPU_ON success", ret_success); 127e14e6ba5SAlexandru Elisei failed = true; 128e14e6ba5SAlexandru Elisei } 129e14e6ba5SAlexandru Elisei 130bec58c1cSLevente Kurusa return !failed; 131bec58c1cSLevente Kurusa } 132bec58c1cSLevente Kurusa 133bec58c1cSLevente Kurusa int main(void) 134bec58c1cSLevente Kurusa { 135bec58c1cSLevente Kurusa int ver = psci_invoke(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); 136bec58c1cSLevente Kurusa 137da5b8576SAndre Przywara report_prefix_push("psci"); 138da5b8576SAndre Przywara 139bec58c1cSLevente Kurusa if (nr_cpus < 2) { 140bec58c1cSLevente Kurusa report_skip("At least 2 cpus required"); 141bec58c1cSLevente Kurusa goto done; 142bec58c1cSLevente Kurusa } 143bec58c1cSLevente Kurusa 144bec58c1cSLevente Kurusa report_info("PSCI version %d.%d", PSCI_VERSION_MAJOR(ver), 145bec58c1cSLevente Kurusa PSCI_VERSION_MINOR(ver)); 146a299895bSThomas Huth report(psci_invalid_function(), "invalid-function"); 147a299895bSThomas Huth report(psci_affinity_info_on(), "affinity-info-on"); 148a299895bSThomas Huth report(psci_affinity_info_off(), "affinity-info-off"); 149f082e37fSAndrew Jones 150f082e37fSAndrew Jones if (ERRATA(6c7a5dce22b3)) 151a299895bSThomas Huth report(psci_cpu_on_test(), "cpu-on"); 152f082e37fSAndrew Jones else 153f082e37fSAndrew Jones report_skip("Skipping unsafe cpu-on test. Set ERRATA_6c7a5dce22b3=y to enable."); 154bec58c1cSLevente Kurusa 155bec58c1cSLevente Kurusa done: 156bec58c1cSLevente Kurusa #if 0 157bec58c1cSLevente Kurusa report_summary(); 158bec58c1cSLevente Kurusa psci_invoke(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 159*198dfd0eSJanis Schoetterl-Glausch report_fail("system-off"); 160bec58c1cSLevente Kurusa return 1; /* only reaches here if system-off fails */ 161bec58c1cSLevente Kurusa #else 162bec58c1cSLevente Kurusa return report_summary(); 163bec58c1cSLevente Kurusa #endif 164bec58c1cSLevente Kurusa } 165