Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/platforms/85xx/smp.c
10820 views
1
/*
2
* Author: Andy Fleming <[email protected]>
3
* Kumar Gala <[email protected]>
4
*
5
* Copyright 2006-2008 Freescale Semiconductor Inc.
6
*
7
* This program is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License as published by the
9
* Free Software Foundation; either version 2 of the License, or (at your
10
* option) any later version.
11
*/
12
13
#include <linux/stddef.h>
14
#include <linux/kernel.h>
15
#include <linux/init.h>
16
#include <linux/delay.h>
17
#include <linux/of.h>
18
#include <linux/kexec.h>
19
#include <linux/highmem.h>
20
21
#include <asm/machdep.h>
22
#include <asm/pgtable.h>
23
#include <asm/page.h>
24
#include <asm/mpic.h>
25
#include <asm/cacheflush.h>
26
#include <asm/dbell.h>
27
28
#include <sysdev/fsl_soc.h>
29
#include <sysdev/mpic.h>
30
31
extern void __early_start(void);
32
33
#define BOOT_ENTRY_ADDR_UPPER 0
34
#define BOOT_ENTRY_ADDR_LOWER 1
35
#define BOOT_ENTRY_R3_UPPER 2
36
#define BOOT_ENTRY_R3_LOWER 3
37
#define BOOT_ENTRY_RESV 4
38
#define BOOT_ENTRY_PIR 5
39
#define BOOT_ENTRY_R6_UPPER 6
40
#define BOOT_ENTRY_R6_LOWER 7
41
#define NUM_BOOT_ENTRY 8
42
#define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32))
43
44
static int __init
45
smp_85xx_kick_cpu(int nr)
46
{
47
unsigned long flags;
48
const u64 *cpu_rel_addr;
49
__iomem u32 *bptr_vaddr;
50
struct device_node *np;
51
int n = 0;
52
int ioremappable;
53
54
WARN_ON (nr < 0 || nr >= NR_CPUS);
55
56
pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
57
58
np = of_get_cpu_node(nr, NULL);
59
cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL);
60
61
if (cpu_rel_addr == NULL) {
62
printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr);
63
return -ENOENT;
64
}
65
66
/*
67
* A secondary core could be in a spinloop in the bootpage
68
* (0xfffff000), somewhere in highmem, or somewhere in lowmem.
69
* The bootpage and highmem can be accessed via ioremap(), but
70
* we need to directly access the spinloop if its in lowmem.
71
*/
72
ioremappable = *cpu_rel_addr > virt_to_phys(high_memory);
73
74
/* Map the spin table */
75
if (ioremappable)
76
bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
77
else
78
bptr_vaddr = phys_to_virt(*cpu_rel_addr);
79
80
local_irq_save(flags);
81
82
out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
83
#ifdef CONFIG_PPC32
84
out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
85
86
if (!ioremappable)
87
flush_dcache_range((ulong)bptr_vaddr,
88
(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
89
90
/* Wait a bit for the CPU to ack. */
91
while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
92
mdelay(1);
93
#else
94
smp_generic_kick_cpu(nr);
95
96
out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
97
__pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
98
99
if (!ioremappable)
100
flush_dcache_range((ulong)bptr_vaddr,
101
(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
102
#endif
103
104
local_irq_restore(flags);
105
106
if (ioremappable)
107
iounmap(bptr_vaddr);
108
109
pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
110
111
return 0;
112
}
113
114
static void __init
115
smp_85xx_setup_cpu(int cpu_nr)
116
{
117
mpic_setup_this_cpu();
118
if (cpu_has_feature(CPU_FTR_DBELL))
119
doorbell_setup_this_cpu();
120
}
121
122
struct smp_ops_t smp_85xx_ops = {
123
.kick_cpu = smp_85xx_kick_cpu,
124
#ifdef CONFIG_KEXEC
125
.give_timebase = smp_generic_give_timebase,
126
.take_timebase = smp_generic_take_timebase,
127
#endif
128
};
129
130
#ifdef CONFIG_KEXEC
131
atomic_t kexec_down_cpus = ATOMIC_INIT(0);
132
133
void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
134
{
135
local_irq_disable();
136
137
if (secondary) {
138
atomic_inc(&kexec_down_cpus);
139
/* loop forever */
140
while (1);
141
}
142
}
143
144
static void mpc85xx_smp_kexec_down(void *arg)
145
{
146
if (ppc_md.kexec_cpu_down)
147
ppc_md.kexec_cpu_down(0,1);
148
}
149
150
static void map_and_flush(unsigned long paddr)
151
{
152
struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
153
unsigned long kaddr = (unsigned long)kmap(page);
154
155
flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
156
kunmap(page);
157
}
158
159
/**
160
* Before we reset the other cores, we need to flush relevant cache
161
* out to memory so we don't get anything corrupted, some of these flushes
162
* are performed out of an overabundance of caution as interrupts are not
163
* disabled yet and we can switch cores
164
*/
165
static void mpc85xx_smp_flush_dcache_kexec(struct kimage *image)
166
{
167
kimage_entry_t *ptr, entry;
168
unsigned long paddr;
169
int i;
170
171
if (image->type == KEXEC_TYPE_DEFAULT) {
172
/* normal kexec images are stored in temporary pages */
173
for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
174
ptr = (entry & IND_INDIRECTION) ?
175
phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
176
if (!(entry & IND_DESTINATION)) {
177
map_and_flush(entry);
178
}
179
}
180
/* flush out last IND_DONE page */
181
map_and_flush(entry);
182
} else {
183
/* crash type kexec images are copied to the crash region */
184
for (i = 0; i < image->nr_segments; i++) {
185
struct kexec_segment *seg = &image->segment[i];
186
for (paddr = seg->mem; paddr < seg->mem + seg->memsz;
187
paddr += PAGE_SIZE) {
188
map_and_flush(paddr);
189
}
190
}
191
}
192
193
/* also flush the kimage struct to be passed in as well */
194
flush_dcache_range((unsigned long)image,
195
(unsigned long)image + sizeof(*image));
196
}
197
198
static void mpc85xx_smp_machine_kexec(struct kimage *image)
199
{
200
int timeout = INT_MAX;
201
int i, num_cpus = num_present_cpus();
202
203
mpc85xx_smp_flush_dcache_kexec(image);
204
205
if (image->type == KEXEC_TYPE_DEFAULT)
206
smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
207
208
while ( (atomic_read(&kexec_down_cpus) != (num_cpus - 1)) &&
209
( timeout > 0 ) )
210
{
211
timeout--;
212
}
213
214
if ( !timeout )
215
printk(KERN_ERR "Unable to bring down secondary cpu(s)");
216
217
for (i = 0; i < num_cpus; i++)
218
{
219
if ( i == smp_processor_id() ) continue;
220
mpic_reset_core(i);
221
}
222
223
default_machine_kexec(image);
224
}
225
#endif /* CONFIG_KEXEC */
226
227
void __init mpc85xx_smp_init(void)
228
{
229
struct device_node *np;
230
231
np = of_find_node_by_type(NULL, "open-pic");
232
if (np) {
233
smp_85xx_ops.probe = smp_mpic_probe;
234
smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu;
235
smp_85xx_ops.message_pass = smp_mpic_message_pass;
236
}
237
238
if (cpu_has_feature(CPU_FTR_DBELL)) {
239
smp_85xx_ops.message_pass = smp_muxed_ipi_message_pass;
240
smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
241
}
242
243
BUG_ON(!smp_85xx_ops.message_pass);
244
245
smp_ops = &smp_85xx_ops;
246
247
#ifdef CONFIG_KEXEC
248
ppc_md.kexec_cpu_down = mpc85xx_smp_kexec_cpu_down;
249
ppc_md.machine_kexec = mpc85xx_smp_machine_kexec;
250
#endif
251
}
252
253