0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/init.h>
0010 #include <linux/smp.h>
0011 #include <linux/of.h>
0012 #include <linux/delay.h>
0013 #include <linux/psci.h>
0014
0015 #include <uapi/linux/psci.h>
0016
0017 #include <asm/psci.h>
0018 #include <asm/smp_plat.h>
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 extern void secondary_startup(void);
0044
0045 static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle)
0046 {
0047 if (psci_ops.cpu_on)
0048 return psci_ops.cpu_on(cpu_logical_map(cpu),
0049 virt_to_idmap(&secondary_startup));
0050 return -ENODEV;
0051 }
0052
0053 #ifdef CONFIG_HOTPLUG_CPU
0054 static int psci_cpu_disable(unsigned int cpu)
0055 {
0056
0057 if (!psci_ops.cpu_off)
0058 return -EOPNOTSUPP;
0059
0060
0061 if (psci_tos_resident_on(cpu))
0062 return -EPERM;
0063
0064 return 0;
0065 }
0066
0067 static void psci_cpu_die(unsigned int cpu)
0068 {
0069 u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN <<
0070 PSCI_0_2_POWER_STATE_TYPE_SHIFT;
0071
0072 if (psci_ops.cpu_off)
0073 psci_ops.cpu_off(state);
0074
0075
0076 panic("psci: cpu %d failed to shutdown\n", cpu);
0077 }
0078
0079 static int psci_cpu_kill(unsigned int cpu)
0080 {
0081 int err, i;
0082
0083 if (!psci_ops.affinity_info)
0084 return 1;
0085
0086
0087
0088
0089
0090
0091 for (i = 0; i < 10; i++) {
0092 err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
0093 if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
0094 pr_info("CPU%d killed.\n", cpu);
0095 return 1;
0096 }
0097
0098 msleep(10);
0099 pr_info("Retrying again to check for CPU kill\n");
0100 }
0101
0102 pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n",
0103 cpu, err);
0104
0105 return 0;
0106 }
0107
0108 #endif
0109
0110 bool __init psci_smp_available(void)
0111 {
0112
0113 return (psci_ops.cpu_on != NULL);
0114 }
0115
0116 const struct smp_operations psci_smp_ops __initconst = {
0117 .smp_boot_secondary = psci_boot_secondary,
0118 #ifdef CONFIG_HOTPLUG_CPU
0119 .cpu_disable = psci_cpu_disable,
0120 .cpu_die = psci_cpu_die,
0121 .cpu_kill = psci_cpu_kill,
0122 #endif
0123 };