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