/* * psci.c - basic PSCI implementation * * Copyright (C) 2015 ARM Limited. All rights reserved. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE.txt file. */ #include #include #include #include #include #ifndef CPU_IDS #error "No MPIDRs provided" #endif static unsigned long branch_table[NR_CPUS]; bakery_ticket_t branch_table_lock[NR_CPUS]; static int psci_store_address(unsigned int cpu, unsigned long address) { if (branch_table[cpu] != PSCI_ADDR_INVALID) return PSCI_RET_ALREADY_ON; branch_table[cpu] = address; return PSCI_RET_SUCCESS; } int psci_cpu_on(unsigned long target_mpidr, unsigned long address) { int ret; unsigned int cpu = find_logical_id(target_mpidr); unsigned int this_cpu = find_logical_id(read_mpidr()); if (cpu == MPIDR_INVALID) return PSCI_RET_INVALID_PARAMETERS; bakery_lock(branch_table_lock, this_cpu); ret = psci_store_address(cpu, address); bakery_unlock(branch_table_lock, this_cpu); return ret; } int psci_cpu_off(void) { unsigned long mpidr = read_mpidr(); unsigned int cpu = find_logical_id(mpidr); if (cpu == MPIDR_INVALID) return PSCI_RET_DENIED; branch_table[cpu] = PSCI_ADDR_INVALID; spin(branch_table + cpu, PSCI_ADDR_INVALID, 0); unreachable(); } void __noreturn psci_first_spin(unsigned int cpu) { if (cpu == MPIDR_INVALID) while (1); first_spin(cpu, branch_table + cpu, PSCI_ADDR_INVALID); unreachable(); }