Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/platforms/wsp/scom_smp.c
10818 views
1
/*
2
* SCOM support for A2 platforms
3
*
4
* Copyright 2007-2011 Benjamin Herrenschmidt, David Gibson,
5
* Michael Ellerman, IBM Corp.
6
*
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version
10
* 2 of the License, or (at your option) any later version.
11
*/
12
13
#include <linux/cpumask.h>
14
#include <linux/io.h>
15
#include <linux/of.h>
16
#include <linux/spinlock.h>
17
#include <linux/types.h>
18
19
#include <asm/cputhreads.h>
20
#include <asm/reg_a2.h>
21
#include <asm/scom.h>
22
#include <asm/udbg.h>
23
24
#include "wsp.h"
25
26
#define SCOM_RAMC 0x2a /* Ram Command */
27
#define SCOM_RAMC_TGT1_EXT 0x80000000
28
#define SCOM_RAMC_SRC1_EXT 0x40000000
29
#define SCOM_RAMC_SRC2_EXT 0x20000000
30
#define SCOM_RAMC_SRC3_EXT 0x10000000
31
#define SCOM_RAMC_ENABLE 0x00080000
32
#define SCOM_RAMC_THREADSEL 0x00060000
33
#define SCOM_RAMC_EXECUTE 0x00010000
34
#define SCOM_RAMC_MSR_OVERRIDE 0x00008000
35
#define SCOM_RAMC_MSR_PR 0x00004000
36
#define SCOM_RAMC_MSR_GS 0x00002000
37
#define SCOM_RAMC_FORCE 0x00001000
38
#define SCOM_RAMC_FLUSH 0x00000800
39
#define SCOM_RAMC_INTERRUPT 0x00000004
40
#define SCOM_RAMC_ERROR 0x00000002
41
#define SCOM_RAMC_DONE 0x00000001
42
#define SCOM_RAMI 0x29 /* Ram Instruction */
43
#define SCOM_RAMIC 0x28 /* Ram Instruction and Command */
44
#define SCOM_RAMIC_INSN 0xffffffff00000000
45
#define SCOM_RAMD 0x2d /* Ram Data */
46
#define SCOM_RAMDH 0x2e /* Ram Data High */
47
#define SCOM_RAMDL 0x2f /* Ram Data Low */
48
#define SCOM_PCCR0 0x33 /* PC Configuration Register 0 */
49
#define SCOM_PCCR0_ENABLE_DEBUG 0x80000000
50
#define SCOM_PCCR0_ENABLE_RAM 0x40000000
51
#define SCOM_THRCTL 0x30 /* Thread Control and Status */
52
#define SCOM_THRCTL_T0_STOP 0x80000000
53
#define SCOM_THRCTL_T1_STOP 0x40000000
54
#define SCOM_THRCTL_T2_STOP 0x20000000
55
#define SCOM_THRCTL_T3_STOP 0x10000000
56
#define SCOM_THRCTL_T0_STEP 0x08000000
57
#define SCOM_THRCTL_T1_STEP 0x04000000
58
#define SCOM_THRCTL_T2_STEP 0x02000000
59
#define SCOM_THRCTL_T3_STEP 0x01000000
60
#define SCOM_THRCTL_T0_RUN 0x00800000
61
#define SCOM_THRCTL_T1_RUN 0x00400000
62
#define SCOM_THRCTL_T2_RUN 0x00200000
63
#define SCOM_THRCTL_T3_RUN 0x00100000
64
#define SCOM_THRCTL_T0_PM 0x00080000
65
#define SCOM_THRCTL_T1_PM 0x00040000
66
#define SCOM_THRCTL_T2_PM 0x00020000
67
#define SCOM_THRCTL_T3_PM 0x00010000
68
#define SCOM_THRCTL_T0_UDE 0x00008000
69
#define SCOM_THRCTL_T1_UDE 0x00004000
70
#define SCOM_THRCTL_T2_UDE 0x00002000
71
#define SCOM_THRCTL_T3_UDE 0x00001000
72
#define SCOM_THRCTL_ASYNC_DIS 0x00000800
73
#define SCOM_THRCTL_TB_DIS 0x00000400
74
#define SCOM_THRCTL_DEC_DIS 0x00000200
75
#define SCOM_THRCTL_AND 0x31 /* Thread Control and Status */
76
#define SCOM_THRCTL_OR 0x32 /* Thread Control and Status */
77
78
79
static DEFINE_PER_CPU(scom_map_t, scom_ptrs);
80
81
static scom_map_t get_scom(int cpu, struct device_node *np, int *first_thread)
82
{
83
scom_map_t scom = per_cpu(scom_ptrs, cpu);
84
int tcpu;
85
86
if (scom_map_ok(scom)) {
87
*first_thread = 0;
88
return scom;
89
}
90
91
*first_thread = 1;
92
93
scom = scom_map_device(np, 0);
94
95
for (tcpu = cpu_first_thread_sibling(cpu);
96
tcpu <= cpu_last_thread_sibling(cpu); tcpu++)
97
per_cpu(scom_ptrs, tcpu) = scom;
98
99
/* Hack: for the boot core, this will actually get called on
100
* the second thread up, not the first so our test above will
101
* set first_thread incorrectly. */
102
if (cpu_first_thread_sibling(cpu) == 0)
103
*first_thread = 0;
104
105
return scom;
106
}
107
108
static int a2_scom_ram(scom_map_t scom, int thread, u32 insn, int extmask)
109
{
110
u64 cmd, mask, val;
111
int n = 0;
112
113
cmd = ((u64)insn << 32) | (((u64)extmask & 0xf) << 28)
114
| ((u64)thread << 17) | SCOM_RAMC_ENABLE | SCOM_RAMC_EXECUTE;
115
mask = SCOM_RAMC_DONE | SCOM_RAMC_INTERRUPT | SCOM_RAMC_ERROR;
116
117
scom_write(scom, SCOM_RAMIC, cmd);
118
119
while (!((val = scom_read(scom, SCOM_RAMC)) & mask)) {
120
pr_devel("Waiting on RAMC = 0x%llx\n", val);
121
if (++n == 3) {
122
pr_err("RAMC timeout on instruction 0x%08x, thread %d\n",
123
insn, thread);
124
return -1;
125
}
126
}
127
128
if (val & SCOM_RAMC_INTERRUPT) {
129
pr_err("RAMC interrupt on instruction 0x%08x, thread %d\n",
130
insn, thread);
131
return -SCOM_RAMC_INTERRUPT;
132
}
133
134
if (val & SCOM_RAMC_ERROR) {
135
pr_err("RAMC error on instruction 0x%08x, thread %d\n",
136
insn, thread);
137
return -SCOM_RAMC_ERROR;
138
}
139
140
return 0;
141
}
142
143
static int a2_scom_getgpr(scom_map_t scom, int thread, int gpr, int alt,
144
u64 *out_gpr)
145
{
146
int rc;
147
148
/* or rN, rN, rN */
149
u32 insn = 0x7c000378 | (gpr << 21) | (gpr << 16) | (gpr << 11);
150
rc = a2_scom_ram(scom, thread, insn, alt ? 0xf : 0x0);
151
if (rc)
152
return rc;
153
154
*out_gpr = scom_read(scom, SCOM_RAMD);
155
156
return 0;
157
}
158
159
static int a2_scom_getspr(scom_map_t scom, int thread, int spr, u64 *out_spr)
160
{
161
int rc, sprhi, sprlo;
162
u32 insn;
163
164
sprhi = spr >> 5;
165
sprlo = spr & 0x1f;
166
insn = 0x7c2002a6 | (sprlo << 16) | (sprhi << 11); /* mfspr r1,spr */
167
168
if (spr == 0x0ff0)
169
insn = 0x7c2000a6; /* mfmsr r1 */
170
171
rc = a2_scom_ram(scom, thread, insn, 0xf);
172
if (rc)
173
return rc;
174
return a2_scom_getgpr(scom, thread, 1, 1, out_spr);
175
}
176
177
static int a2_scom_setgpr(scom_map_t scom, int thread, int gpr,
178
int alt, u64 val)
179
{
180
u32 lis = 0x3c000000 | (gpr << 21);
181
u32 li = 0x38000000 | (gpr << 21);
182
u32 oris = 0x64000000 | (gpr << 21) | (gpr << 16);
183
u32 ori = 0x60000000 | (gpr << 21) | (gpr << 16);
184
u32 rldicr32 = 0x780007c6 | (gpr << 21) | (gpr << 16);
185
u32 highest = val >> 48;
186
u32 higher = (val >> 32) & 0xffff;
187
u32 high = (val >> 16) & 0xffff;
188
u32 low = val & 0xffff;
189
int lext = alt ? 0x8 : 0x0;
190
int oext = alt ? 0xf : 0x0;
191
int rc = 0;
192
193
if (highest)
194
rc |= a2_scom_ram(scom, thread, lis | highest, lext);
195
196
if (higher) {
197
if (highest)
198
rc |= a2_scom_ram(scom, thread, oris | higher, oext);
199
else
200
rc |= a2_scom_ram(scom, thread, li | higher, lext);
201
}
202
203
if (highest || higher)
204
rc |= a2_scom_ram(scom, thread, rldicr32, oext);
205
206
if (high) {
207
if (highest || higher)
208
rc |= a2_scom_ram(scom, thread, oris | high, oext);
209
else
210
rc |= a2_scom_ram(scom, thread, lis | high, lext);
211
}
212
213
if (highest || higher || high)
214
rc |= a2_scom_ram(scom, thread, ori | low, oext);
215
else
216
rc |= a2_scom_ram(scom, thread, li | low, lext);
217
218
return rc;
219
}
220
221
static int a2_scom_setspr(scom_map_t scom, int thread, int spr, u64 val)
222
{
223
int sprhi = spr >> 5;
224
int sprlo = spr & 0x1f;
225
/* mtspr spr, r1 */
226
u32 insn = 0x7c2003a6 | (sprlo << 16) | (sprhi << 11);
227
228
if (spr == 0x0ff0)
229
insn = 0x7c200124; /* mtmsr r1 */
230
231
if (a2_scom_setgpr(scom, thread, 1, 1, val))
232
return -1;
233
234
return a2_scom_ram(scom, thread, insn, 0xf);
235
}
236
237
static int a2_scom_initial_tlb(scom_map_t scom, int thread)
238
{
239
extern u32 a2_tlbinit_code_start[], a2_tlbinit_code_end[];
240
extern u32 a2_tlbinit_after_iprot_flush[];
241
extern u32 a2_tlbinit_after_linear_map[];
242
u32 assoc, entries, i;
243
u64 epn, tlbcfg;
244
u32 *p;
245
int rc;
246
247
/* Invalidate all entries (including iprot) */
248
249
rc = a2_scom_getspr(scom, thread, SPRN_TLB0CFG, &tlbcfg);
250
if (rc)
251
goto scom_fail;
252
entries = tlbcfg & TLBnCFG_N_ENTRY;
253
assoc = (tlbcfg & TLBnCFG_ASSOC) >> 24;
254
epn = 0;
255
256
/* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */
257
a2_scom_setspr(scom, thread, SPRN_MMUCR2, 0x000a7531);
258
/* Set MMUCR3 to write all thids bit to the TLB */
259
a2_scom_setspr(scom, thread, SPRN_MMUCR3, 0x0000000f);
260
261
/* Set MAS1 for 1G page size, and MAS2 to our initial EPN */
262
a2_scom_setspr(scom, thread, SPRN_MAS1, MAS1_TSIZE(BOOK3E_PAGESZ_1GB));
263
a2_scom_setspr(scom, thread, SPRN_MAS2, epn);
264
for (i = 0; i < entries; i++) {
265
266
a2_scom_setspr(scom, thread, SPRN_MAS0, MAS0_ESEL(i % assoc));
267
268
/* tlbwe */
269
rc = a2_scom_ram(scom, thread, 0x7c0007a4, 0);
270
if (rc)
271
goto scom_fail;
272
273
/* Next entry is new address? */
274
if((i + 1) % assoc == 0) {
275
epn += (1 << 30);
276
a2_scom_setspr(scom, thread, SPRN_MAS2, epn);
277
}
278
}
279
280
/* Setup args for linear mapping */
281
rc = a2_scom_setgpr(scom, thread, 3, 0, MAS0_TLBSEL(0));
282
if (rc)
283
goto scom_fail;
284
285
/* Linear mapping */
286
for (p = a2_tlbinit_code_start; p < a2_tlbinit_after_linear_map; p++) {
287
rc = a2_scom_ram(scom, thread, *p, 0);
288
if (rc)
289
goto scom_fail;
290
}
291
292
/*
293
* For the boot thread, between the linear mapping and the debug
294
* mappings there is a loop to flush iprot mappings. Ramming doesn't do
295
* branches, but the secondary threads don't need to be nearly as smart
296
* (i.e. we don't need to worry about invalidating the mapping we're
297
* standing on).
298
*/
299
300
/* Debug mappings. Expects r11 = MAS0 from linear map (set above) */
301
for (p = a2_tlbinit_after_iprot_flush; p < a2_tlbinit_code_end; p++) {
302
rc = a2_scom_ram(scom, thread, *p, 0);
303
if (rc)
304
goto scom_fail;
305
}
306
307
scom_fail:
308
if (rc)
309
pr_err("Setting up initial TLB failed, err %d\n", rc);
310
311
if (rc == -SCOM_RAMC_INTERRUPT) {
312
/* Interrupt, dump some status */
313
int rc[10];
314
u64 iar, srr0, srr1, esr, mas0, mas1, mas2, mas7_3, mas8, ccr2;
315
rc[0] = a2_scom_getspr(scom, thread, SPRN_IAR, &iar);
316
rc[1] = a2_scom_getspr(scom, thread, SPRN_SRR0, &srr0);
317
rc[2] = a2_scom_getspr(scom, thread, SPRN_SRR1, &srr1);
318
rc[3] = a2_scom_getspr(scom, thread, SPRN_ESR, &esr);
319
rc[4] = a2_scom_getspr(scom, thread, SPRN_MAS0, &mas0);
320
rc[5] = a2_scom_getspr(scom, thread, SPRN_MAS1, &mas1);
321
rc[6] = a2_scom_getspr(scom, thread, SPRN_MAS2, &mas2);
322
rc[7] = a2_scom_getspr(scom, thread, SPRN_MAS7_MAS3, &mas7_3);
323
rc[8] = a2_scom_getspr(scom, thread, SPRN_MAS8, &mas8);
324
rc[9] = a2_scom_getspr(scom, thread, SPRN_A2_CCR2, &ccr2);
325
pr_err(" -> retreived IAR =0x%llx (err %d)\n", iar, rc[0]);
326
pr_err(" retreived SRR0=0x%llx (err %d)\n", srr0, rc[1]);
327
pr_err(" retreived SRR1=0x%llx (err %d)\n", srr1, rc[2]);
328
pr_err(" retreived ESR =0x%llx (err %d)\n", esr, rc[3]);
329
pr_err(" retreived MAS0=0x%llx (err %d)\n", mas0, rc[4]);
330
pr_err(" retreived MAS1=0x%llx (err %d)\n", mas1, rc[5]);
331
pr_err(" retreived MAS2=0x%llx (err %d)\n", mas2, rc[6]);
332
pr_err(" retreived MS73=0x%llx (err %d)\n", mas7_3, rc[7]);
333
pr_err(" retreived MAS8=0x%llx (err %d)\n", mas8, rc[8]);
334
pr_err(" retreived CCR2=0x%llx (err %d)\n", ccr2, rc[9]);
335
}
336
337
return rc;
338
}
339
340
int __devinit a2_scom_startup_cpu(unsigned int lcpu, int thr_idx,
341
struct device_node *np)
342
{
343
u64 init_iar, init_msr, init_ccr2;
344
unsigned long start_here;
345
int rc, core_setup;
346
scom_map_t scom;
347
u64 pccr0;
348
349
scom = get_scom(lcpu, np, &core_setup);
350
if (!scom) {
351
printk(KERN_ERR "Couldn't map SCOM for CPU%d\n", lcpu);
352
return -1;
353
}
354
355
pr_devel("Bringing up CPU%d using SCOM...\n", lcpu);
356
357
pccr0 = scom_read(scom, SCOM_PCCR0);
358
scom_write(scom, SCOM_PCCR0, pccr0 | SCOM_PCCR0_ENABLE_DEBUG |
359
SCOM_PCCR0_ENABLE_RAM);
360
361
/* Stop the thead with THRCTL. If we are setting up the TLB we stop all
362
* threads. We also disable asynchronous interrupts while RAMing.
363
*/
364
if (core_setup)
365
scom_write(scom, SCOM_THRCTL_OR,
366
SCOM_THRCTL_T0_STOP |
367
SCOM_THRCTL_T1_STOP |
368
SCOM_THRCTL_T2_STOP |
369
SCOM_THRCTL_T3_STOP |
370
SCOM_THRCTL_ASYNC_DIS);
371
else
372
scom_write(scom, SCOM_THRCTL_OR, SCOM_THRCTL_T0_STOP >> thr_idx);
373
374
/* Flush its pipeline just in case */
375
scom_write(scom, SCOM_RAMC, ((u64)thr_idx << 17) |
376
SCOM_RAMC_FLUSH | SCOM_RAMC_ENABLE);
377
378
a2_scom_getspr(scom, thr_idx, SPRN_IAR, &init_iar);
379
a2_scom_getspr(scom, thr_idx, 0x0ff0, &init_msr);
380
a2_scom_getspr(scom, thr_idx, SPRN_A2_CCR2, &init_ccr2);
381
382
/* Set MSR to MSR_CM (0x0ff0 is magic value for MSR_CM) */
383
rc = a2_scom_setspr(scom, thr_idx, 0x0ff0, MSR_CM);
384
if (rc) {
385
pr_err("Failed to set MSR ! err %d\n", rc);
386
return rc;
387
}
388
389
/* RAM in an sync/isync for the sake of it */
390
a2_scom_ram(scom, thr_idx, 0x7c0004ac, 0);
391
a2_scom_ram(scom, thr_idx, 0x4c00012c, 0);
392
393
if (core_setup) {
394
pr_devel("CPU%d is first thread in core, initializing TLB...\n",
395
lcpu);
396
rc = a2_scom_initial_tlb(scom, thr_idx);
397
if (rc)
398
goto fail;
399
}
400
401
start_here = *(unsigned long *)(core_setup ? generic_secondary_smp_init
402
: generic_secondary_thread_init);
403
pr_devel("CPU%d entry point at 0x%lx...\n", lcpu, start_here);
404
405
rc |= a2_scom_setspr(scom, thr_idx, SPRN_IAR, start_here);
406
rc |= a2_scom_setgpr(scom, thr_idx, 3, 0,
407
get_hard_smp_processor_id(lcpu));
408
/*
409
* Tell book3e_secondary_core_init not to set up the TLB, we've
410
* already done that.
411
*/
412
rc |= a2_scom_setgpr(scom, thr_idx, 4, 0, 1);
413
414
rc |= a2_scom_setspr(scom, thr_idx, SPRN_TENS, 0x1 << thr_idx);
415
416
scom_write(scom, SCOM_RAMC, 0);
417
scom_write(scom, SCOM_THRCTL_AND, ~(SCOM_THRCTL_T0_STOP >> thr_idx));
418
scom_write(scom, SCOM_PCCR0, pccr0);
419
fail:
420
pr_devel(" SCOM initialization %s\n", rc ? "failed" : "succeeded");
421
if (rc) {
422
pr_err("Old IAR=0x%08llx MSR=0x%08llx CCR2=0x%08llx\n",
423
init_iar, init_msr, init_ccr2);
424
}
425
426
return rc;
427
}
428
429