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