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