cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

psci.c (2699B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 * Copyright (C) 2013 ARM Limited
      5 *
      6 * Author: Will Deacon <will.deacon@arm.com>
      7 */
      8
      9#define pr_fmt(fmt) "psci: " fmt
     10
     11#include <linux/init.h>
     12#include <linux/of.h>
     13#include <linux/smp.h>
     14#include <linux/delay.h>
     15#include <linux/psci.h>
     16#include <linux/mm.h>
     17
     18#include <uapi/linux/psci.h>
     19
     20#include <asm/cpu_ops.h>
     21#include <asm/errno.h>
     22#include <asm/smp_plat.h>
     23
     24static int __init cpu_psci_cpu_init(unsigned int cpu)
     25{
     26	return 0;
     27}
     28
     29static int __init cpu_psci_cpu_prepare(unsigned int cpu)
     30{
     31	if (!psci_ops.cpu_on) {
     32		pr_err("no cpu_on method, not booting CPU%d\n", cpu);
     33		return -ENODEV;
     34	}
     35
     36	return 0;
     37}
     38
     39static int cpu_psci_cpu_boot(unsigned int cpu)
     40{
     41	phys_addr_t pa_secondary_entry = __pa_symbol(function_nocfi(secondary_entry));
     42	int err = psci_ops.cpu_on(cpu_logical_map(cpu), pa_secondary_entry);
     43	if (err)
     44		pr_err("failed to boot CPU%d (%d)\n", cpu, err);
     45
     46	return err;
     47}
     48
     49#ifdef CONFIG_HOTPLUG_CPU
     50static bool cpu_psci_cpu_can_disable(unsigned int cpu)
     51{
     52	return !psci_tos_resident_on(cpu);
     53}
     54
     55static int cpu_psci_cpu_disable(unsigned int cpu)
     56{
     57	/* Fail early if we don't have CPU_OFF support */
     58	if (!psci_ops.cpu_off)
     59		return -EOPNOTSUPP;
     60
     61	/* Trusted OS will deny CPU_OFF */
     62	if (psci_tos_resident_on(cpu))
     63		return -EPERM;
     64
     65	return 0;
     66}
     67
     68static void cpu_psci_cpu_die(unsigned int cpu)
     69{
     70	/*
     71	 * There are no known implementations of PSCI actually using the
     72	 * power state field, pass a sensible default for now.
     73	 */
     74	u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN <<
     75		    PSCI_0_2_POWER_STATE_TYPE_SHIFT;
     76
     77	psci_ops.cpu_off(state);
     78}
     79
     80static int cpu_psci_cpu_kill(unsigned int cpu)
     81{
     82	int err;
     83	unsigned long start, end;
     84
     85	if (!psci_ops.affinity_info)
     86		return 0;
     87	/*
     88	 * cpu_kill could race with cpu_die and we can
     89	 * potentially end up declaring this cpu undead
     90	 * while it is dying. So, try again a few times.
     91	 */
     92
     93	start = jiffies;
     94	end = start + msecs_to_jiffies(100);
     95	do {
     96		err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
     97		if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
     98			pr_info("CPU%d killed (polled %d ms)\n", cpu,
     99				jiffies_to_msecs(jiffies - start));
    100			return 0;
    101		}
    102
    103		usleep_range(100, 1000);
    104	} while (time_before(jiffies, end));
    105
    106	pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n",
    107			cpu, err);
    108	return -ETIMEDOUT;
    109}
    110#endif
    111
    112const struct cpu_operations cpu_psci_ops = {
    113	.name		= "psci",
    114	.cpu_init	= cpu_psci_cpu_init,
    115	.cpu_prepare	= cpu_psci_cpu_prepare,
    116	.cpu_boot	= cpu_psci_cpu_boot,
    117#ifdef CONFIG_HOTPLUG_CPU
    118	.cpu_can_disable = cpu_psci_cpu_can_disable,
    119	.cpu_disable	= cpu_psci_cpu_disable,
    120	.cpu_die	= cpu_psci_cpu_die,
    121	.cpu_kill	= cpu_psci_cpu_kill,
    122#endif
    123};
    124