blob: fad6f5d7785e837074fe82251924c46ab75bdf21 [file] [log] [blame]
/*
* 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 <stdint.h>
#include <bakery_lock.h>
#include <cpu.h>
#include <psci.h>
#include <spin.h>
#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();
}