1 #include <xen/acpi.h>
2 #include <xen/cpu.h>
3 #include <xen/device_tree.h>
4 #include <xen/lib.h>
5 #include <xen/init.h>
6 #include <xen/errno.h>
7 #include <xen/mm.h>
8 #include <xen/smp.h>
9 #include <xen/vmap.h>
10 #include <asm/io.h>
11 #include <asm/psci.h>
12
13 struct smp_enable_ops {
14 int (*prepare_cpu)(int cpu);
15 };
16
17 static paddr_t cpu_release_addr[NR_CPUS];
18 static struct smp_enable_ops smp_enable_ops[NR_CPUS];
19
smp_spin_table_cpu_up(int cpu)20 static int __init smp_spin_table_cpu_up(int cpu)
21 {
22 paddr_t __iomem *release;
23
24 if (!cpu_release_addr[cpu])
25 {
26 printk("CPU%d: No release addr\n", cpu);
27 return -ENODEV;
28 }
29
30 release = ioremap_nocache(cpu_release_addr[cpu], 8);
31 if ( !release )
32 {
33 dprintk(XENLOG_ERR, "CPU%d: Unable to map release address\n", cpu);
34 return -EFAULT;
35 }
36
37 writeq(__pa(init_secondary), release);
38
39 iounmap(release);
40
41 sev();
42
43 return 0;
44 }
45
smp_spin_table_init(int cpu,struct dt_device_node * dn)46 static void __init smp_spin_table_init(int cpu, struct dt_device_node *dn)
47 {
48 if ( !dt_property_read_u64(dn, "cpu-release-addr", &cpu_release_addr[cpu]) )
49 {
50 printk("CPU%d has no cpu-release-addr\n", cpu);
51 return;
52 }
53
54 smp_enable_ops[cpu].prepare_cpu = smp_spin_table_cpu_up;
55 }
56
smp_psci_init(int cpu)57 static int __init smp_psci_init(int cpu)
58 {
59 if ( !psci_ver )
60 {
61 printk("CPU%d asks for PSCI, but DTB has no PSCI node\n", cpu);
62 return -ENODEV;
63 }
64
65 smp_enable_ops[cpu].prepare_cpu = call_psci_cpu_on;
66 return 0;
67 }
68
arch_smp_init(void)69 int __init arch_smp_init(void)
70 {
71 /* Nothing */
72 return 0;
73 }
74
dt_arch_cpu_init(int cpu,struct dt_device_node * dn)75 static int __init dt_arch_cpu_init(int cpu, struct dt_device_node *dn)
76 {
77 const char *enable_method;
78
79 enable_method = dt_get_property(dn, "enable-method", NULL);
80 if (!enable_method)
81 {
82 printk("CPU%d has no enable method\n", cpu);
83 return -EINVAL;
84 }
85
86 if ( !strcmp(enable_method, "spin-table") )
87 smp_spin_table_init(cpu, dn);
88 else if ( !strcmp(enable_method, "psci") )
89 return smp_psci_init(cpu);
90 else
91 {
92 printk("CPU%d has unknown enable method \"%s\"\n", cpu, enable_method);
93 return -EINVAL;
94 }
95
96 return 0;
97 }
98
arch_cpu_init(int cpu,struct dt_device_node * dn)99 int __init arch_cpu_init(int cpu, struct dt_device_node *dn)
100 {
101 if ( acpi_disabled )
102 return dt_arch_cpu_init(cpu, dn);
103 else
104 /* acpi only supports psci at present */
105 return smp_psci_init(cpu);
106 }
107
arch_cpu_up(int cpu)108 int arch_cpu_up(int cpu)
109 {
110 int rc;
111
112 if ( !smp_enable_ops[cpu].prepare_cpu )
113 return -ENODEV;
114
115 update_boot_mapping(true);
116
117 rc = smp_enable_ops[cpu].prepare_cpu(cpu);
118 if ( rc )
119 update_boot_mapping(false);
120
121 return rc;
122 }
123
arch_cpu_up_finish(void)124 void arch_cpu_up_finish(void)
125 {
126 update_boot_mapping(false);
127 }
128
129 /*
130 * Local variables:
131 * mode: C
132 * c-file-style: "BSD"
133 * c-basic-offset: 4
134 * indent-tabs-mode: nil
135 * End:
136 */
137