diff options
Diffstat (limited to 'arch/ppc64/kernel/misc.S')
-rw-r--r-- | arch/ppc64/kernel/misc.S | 940 |
1 files changed, 0 insertions, 940 deletions
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S deleted file mode 100644 index 5e089deb0a2b..000000000000 --- a/arch/ppc64/kernel/misc.S +++ /dev/null | |||
@@ -1,940 +0,0 @@ | |||
1 | /* | ||
2 | * arch/ppc/kernel/misc.S | ||
3 | * | ||
4 | * | ||
5 | * | ||
6 | * This file contains miscellaneous low-level functions. | ||
7 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
8 | * | ||
9 | * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) | ||
10 | * and Paul Mackerras. | ||
11 | * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) | ||
12 | * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version | ||
17 | * 2 of the License, or (at your option) any later version. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/sys.h> | ||
23 | #include <asm/unistd.h> | ||
24 | #include <asm/errno.h> | ||
25 | #include <asm/processor.h> | ||
26 | #include <asm/page.h> | ||
27 | #include <asm/cache.h> | ||
28 | #include <asm/ppc_asm.h> | ||
29 | #include <asm/asm-offsets.h> | ||
30 | #include <asm/cputable.h> | ||
31 | #include <asm/thread_info.h> | ||
32 | |||
33 | .text | ||
34 | |||
35 | /* | ||
36 | * Returns (address we were linked at) - (address we are running at) | ||
37 | * for use before the text and data are mapped to KERNELBASE. | ||
38 | */ | ||
39 | |||
40 | _GLOBAL(reloc_offset) | ||
41 | mflr r0 | ||
42 | bl 1f | ||
43 | 1: mflr r3 | ||
44 | LOADADDR(r4,1b) | ||
45 | sub r3,r4,r3 | ||
46 | mtlr r0 | ||
47 | blr | ||
48 | |||
49 | _GLOBAL(get_msr) | ||
50 | mfmsr r3 | ||
51 | blr | ||
52 | |||
53 | _GLOBAL(get_dar) | ||
54 | mfdar r3 | ||
55 | blr | ||
56 | |||
57 | _GLOBAL(get_srr0) | ||
58 | mfsrr0 r3 | ||
59 | blr | ||
60 | |||
61 | _GLOBAL(get_srr1) | ||
62 | mfsrr1 r3 | ||
63 | blr | ||
64 | |||
65 | _GLOBAL(get_sp) | ||
66 | mr r3,r1 | ||
67 | blr | ||
68 | |||
69 | #ifdef CONFIG_IRQSTACKS | ||
70 | _GLOBAL(call_do_softirq) | ||
71 | mflr r0 | ||
72 | std r0,16(r1) | ||
73 | stdu r1,THREAD_SIZE-112(r3) | ||
74 | mr r1,r3 | ||
75 | bl .__do_softirq | ||
76 | ld r1,0(r1) | ||
77 | ld r0,16(r1) | ||
78 | mtlr r0 | ||
79 | blr | ||
80 | |||
81 | _GLOBAL(call___do_IRQ) | ||
82 | mflr r0 | ||
83 | std r0,16(r1) | ||
84 | stdu r1,THREAD_SIZE-112(r5) | ||
85 | mr r1,r5 | ||
86 | bl .__do_IRQ | ||
87 | ld r1,0(r1) | ||
88 | ld r0,16(r1) | ||
89 | mtlr r0 | ||
90 | blr | ||
91 | #endif /* CONFIG_IRQSTACKS */ | ||
92 | |||
93 | /* | ||
94 | * To be called by C code which needs to do some operations with MMU | ||
95 | * disabled. Note that interrupts have to be disabled by the caller | ||
96 | * prior to calling us. The code called _MUST_ be in the RMO of course | ||
97 | * and part of the linear mapping as we don't attempt to translate the | ||
98 | * stack pointer at all. The function is called with the stack switched | ||
99 | * to this CPU emergency stack | ||
100 | * | ||
101 | * prototype is void *call_with_mmu_off(void *func, void *data); | ||
102 | * | ||
103 | * the called function is expected to be of the form | ||
104 | * | ||
105 | * void *called(void *data); | ||
106 | */ | ||
107 | _GLOBAL(call_with_mmu_off) | ||
108 | mflr r0 /* get link, save it on stackframe */ | ||
109 | std r0,16(r1) | ||
110 | mr r1,r5 /* save old stack ptr */ | ||
111 | ld r1,PACAEMERGSP(r13) /* get emerg. stack */ | ||
112 | subi r1,r1,STACK_FRAME_OVERHEAD | ||
113 | std r0,16(r1) /* save link on emerg. stack */ | ||
114 | std r5,0(r1) /* save old stack ptr in backchain */ | ||
115 | ld r3,0(r3) /* get to real function ptr (assume same TOC) */ | ||
116 | bl 2f /* we need LR to return, continue at label 2 */ | ||
117 | |||
118 | ld r0,16(r1) /* we return here from the call, get LR and */ | ||
119 | ld r1,0(r1) /* .. old stack ptr */ | ||
120 | mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ | ||
121 | mfmsr r4 | ||
122 | ori r4,r4,MSR_IR|MSR_DR | ||
123 | mtspr SPRN_SRR1,r4 | ||
124 | rfid | ||
125 | |||
126 | 2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ | ||
127 | mr r3,r4 /* get parameter */ | ||
128 | mfmsr r0 | ||
129 | ori r0,r0,MSR_IR|MSR_DR | ||
130 | xori r0,r0,MSR_IR|MSR_DR | ||
131 | mtspr SPRN_SRR1,r0 | ||
132 | rfid | ||
133 | |||
134 | |||
135 | .section ".toc","aw" | ||
136 | PPC64_CACHES: | ||
137 | .tc ppc64_caches[TC],ppc64_caches | ||
138 | .section ".text" | ||
139 | |||
140 | /* | ||
141 | * Write any modified data cache blocks out to memory | ||
142 | * and invalidate the corresponding instruction cache blocks. | ||
143 | * | ||
144 | * flush_icache_range(unsigned long start, unsigned long stop) | ||
145 | * | ||
146 | * flush all bytes from start through stop-1 inclusive | ||
147 | */ | ||
148 | |||
149 | _KPROBE(__flush_icache_range) | ||
150 | |||
151 | /* | ||
152 | * Flush the data cache to memory | ||
153 | * | ||
154 | * Different systems have different cache line sizes | ||
155 | * and in some cases i-cache and d-cache line sizes differ from | ||
156 | * each other. | ||
157 | */ | ||
158 | ld r10,PPC64_CACHES@toc(r2) | ||
159 | lwz r7,DCACHEL1LINESIZE(r10)/* Get cache line size */ | ||
160 | addi r5,r7,-1 | ||
161 | andc r6,r3,r5 /* round low to line bdy */ | ||
162 | subf r8,r6,r4 /* compute length */ | ||
163 | add r8,r8,r5 /* ensure we get enough */ | ||
164 | lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ | ||
165 | srw. r8,r8,r9 /* compute line count */ | ||
166 | beqlr /* nothing to do? */ | ||
167 | mtctr r8 | ||
168 | 1: dcbst 0,r6 | ||
169 | add r6,r6,r7 | ||
170 | bdnz 1b | ||
171 | sync | ||
172 | |||
173 | /* Now invalidate the instruction cache */ | ||
174 | |||
175 | lwz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ | ||
176 | addi r5,r7,-1 | ||
177 | andc r6,r3,r5 /* round low to line bdy */ | ||
178 | subf r8,r6,r4 /* compute length */ | ||
179 | add r8,r8,r5 | ||
180 | lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ | ||
181 | srw. r8,r8,r9 /* compute line count */ | ||
182 | beqlr /* nothing to do? */ | ||
183 | mtctr r8 | ||
184 | 2: icbi 0,r6 | ||
185 | add r6,r6,r7 | ||
186 | bdnz 2b | ||
187 | isync | ||
188 | blr | ||
189 | |||
190 | .text | ||
191 | /* | ||
192 | * Like above, but only do the D-cache. | ||
193 | * | ||
194 | * flush_dcache_range(unsigned long start, unsigned long stop) | ||
195 | * | ||
196 | * flush all bytes from start to stop-1 inclusive | ||
197 | */ | ||
198 | _GLOBAL(flush_dcache_range) | ||
199 | |||
200 | /* | ||
201 | * Flush the data cache to memory | ||
202 | * | ||
203 | * Different systems have different cache line sizes | ||
204 | */ | ||
205 | ld r10,PPC64_CACHES@toc(r2) | ||
206 | lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ | ||
207 | addi r5,r7,-1 | ||
208 | andc r6,r3,r5 /* round low to line bdy */ | ||
209 | subf r8,r6,r4 /* compute length */ | ||
210 | add r8,r8,r5 /* ensure we get enough */ | ||
211 | lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ | ||
212 | srw. r8,r8,r9 /* compute line count */ | ||
213 | beqlr /* nothing to do? */ | ||
214 | mtctr r8 | ||
215 | 0: dcbst 0,r6 | ||
216 | add r6,r6,r7 | ||
217 | bdnz 0b | ||
218 | sync | ||
219 | blr | ||
220 | |||
221 | /* | ||
222 | * Like above, but works on non-mapped physical addresses. | ||
223 | * Use only for non-LPAR setups ! It also assumes real mode | ||
224 | * is cacheable. Used for flushing out the DART before using | ||
225 | * it as uncacheable memory | ||
226 | * | ||
227 | * flush_dcache_phys_range(unsigned long start, unsigned long stop) | ||
228 | * | ||
229 | * flush all bytes from start to stop-1 inclusive | ||
230 | */ | ||
231 | _GLOBAL(flush_dcache_phys_range) | ||
232 | ld r10,PPC64_CACHES@toc(r2) | ||
233 | lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ | ||
234 | addi r5,r7,-1 | ||
235 | andc r6,r3,r5 /* round low to line bdy */ | ||
236 | subf r8,r6,r4 /* compute length */ | ||
237 | add r8,r8,r5 /* ensure we get enough */ | ||
238 | lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ | ||
239 | srw. r8,r8,r9 /* compute line count */ | ||
240 | beqlr /* nothing to do? */ | ||
241 | mfmsr r5 /* Disable MMU Data Relocation */ | ||
242 | ori r0,r5,MSR_DR | ||
243 | xori r0,r0,MSR_DR | ||
244 | sync | ||
245 | mtmsr r0 | ||
246 | sync | ||
247 | isync | ||
248 | mtctr r8 | ||
249 | 0: dcbst 0,r6 | ||
250 | add r6,r6,r7 | ||
251 | bdnz 0b | ||
252 | sync | ||
253 | isync | ||
254 | mtmsr r5 /* Re-enable MMU Data Relocation */ | ||
255 | sync | ||
256 | isync | ||
257 | blr | ||
258 | |||
259 | _GLOBAL(flush_inval_dcache_range) | ||
260 | ld r10,PPC64_CACHES@toc(r2) | ||
261 | lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ | ||
262 | addi r5,r7,-1 | ||
263 | andc r6,r3,r5 /* round low to line bdy */ | ||
264 | subf r8,r6,r4 /* compute length */ | ||
265 | add r8,r8,r5 /* ensure we get enough */ | ||
266 | lwz r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */ | ||
267 | srw. r8,r8,r9 /* compute line count */ | ||
268 | beqlr /* nothing to do? */ | ||
269 | sync | ||
270 | isync | ||
271 | mtctr r8 | ||
272 | 0: dcbf 0,r6 | ||
273 | add r6,r6,r7 | ||
274 | bdnz 0b | ||
275 | sync | ||
276 | isync | ||
277 | blr | ||
278 | |||
279 | |||
280 | /* | ||
281 | * Flush a particular page from the data cache to RAM. | ||
282 | * Note: this is necessary because the instruction cache does *not* | ||
283 | * snoop from the data cache. | ||
284 | * | ||
285 | * void __flush_dcache_icache(void *page) | ||
286 | */ | ||
287 | _GLOBAL(__flush_dcache_icache) | ||
288 | /* | ||
289 | * Flush the data cache to memory | ||
290 | * | ||
291 | * Different systems have different cache line sizes | ||
292 | */ | ||
293 | |||
294 | /* Flush the dcache */ | ||
295 | ld r7,PPC64_CACHES@toc(r2) | ||
296 | clrrdi r3,r3,PAGE_SHIFT /* Page align */ | ||
297 | lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ | ||
298 | lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ | ||
299 | mr r6,r3 | ||
300 | mtctr r4 | ||
301 | 0: dcbst 0,r6 | ||
302 | add r6,r6,r5 | ||
303 | bdnz 0b | ||
304 | sync | ||
305 | |||
306 | /* Now invalidate the icache */ | ||
307 | |||
308 | lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ | ||
309 | lwz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ | ||
310 | mtctr r4 | ||
311 | 1: icbi 0,r3 | ||
312 | add r3,r3,r5 | ||
313 | bdnz 1b | ||
314 | isync | ||
315 | blr | ||
316 | |||
317 | /* | ||
318 | * I/O string operations | ||
319 | * | ||
320 | * insb(port, buf, len) | ||
321 | * outsb(port, buf, len) | ||
322 | * insw(port, buf, len) | ||
323 | * outsw(port, buf, len) | ||
324 | * insl(port, buf, len) | ||
325 | * outsl(port, buf, len) | ||
326 | * insw_ns(port, buf, len) | ||
327 | * outsw_ns(port, buf, len) | ||
328 | * insl_ns(port, buf, len) | ||
329 | * outsl_ns(port, buf, len) | ||
330 | * | ||
331 | * The *_ns versions don't do byte-swapping. | ||
332 | */ | ||
333 | _GLOBAL(_insb) | ||
334 | cmpwi 0,r5,0 | ||
335 | mtctr r5 | ||
336 | subi r4,r4,1 | ||
337 | blelr- | ||
338 | 00: lbz r5,0(r3) | ||
339 | eieio | ||
340 | stbu r5,1(r4) | ||
341 | bdnz 00b | ||
342 | twi 0,r5,0 | ||
343 | isync | ||
344 | blr | ||
345 | |||
346 | _GLOBAL(_outsb) | ||
347 | cmpwi 0,r5,0 | ||
348 | mtctr r5 | ||
349 | subi r4,r4,1 | ||
350 | blelr- | ||
351 | 00: lbzu r5,1(r4) | ||
352 | stb r5,0(r3) | ||
353 | bdnz 00b | ||
354 | sync | ||
355 | blr | ||
356 | |||
357 | _GLOBAL(_insw) | ||
358 | cmpwi 0,r5,0 | ||
359 | mtctr r5 | ||
360 | subi r4,r4,2 | ||
361 | blelr- | ||
362 | 00: lhbrx r5,0,r3 | ||
363 | eieio | ||
364 | sthu r5,2(r4) | ||
365 | bdnz 00b | ||
366 | twi 0,r5,0 | ||
367 | isync | ||
368 | blr | ||
369 | |||
370 | _GLOBAL(_outsw) | ||
371 | cmpwi 0,r5,0 | ||
372 | mtctr r5 | ||
373 | subi r4,r4,2 | ||
374 | blelr- | ||
375 | 00: lhzu r5,2(r4) | ||
376 | sthbrx r5,0,r3 | ||
377 | bdnz 00b | ||
378 | sync | ||
379 | blr | ||
380 | |||
381 | _GLOBAL(_insl) | ||
382 | cmpwi 0,r5,0 | ||
383 | mtctr r5 | ||
384 | subi r4,r4,4 | ||
385 | blelr- | ||
386 | 00: lwbrx r5,0,r3 | ||
387 | eieio | ||
388 | stwu r5,4(r4) | ||
389 | bdnz 00b | ||
390 | twi 0,r5,0 | ||
391 | isync | ||
392 | blr | ||
393 | |||
394 | _GLOBAL(_outsl) | ||
395 | cmpwi 0,r5,0 | ||
396 | mtctr r5 | ||
397 | subi r4,r4,4 | ||
398 | blelr- | ||
399 | 00: lwzu r5,4(r4) | ||
400 | stwbrx r5,0,r3 | ||
401 | bdnz 00b | ||
402 | sync | ||
403 | blr | ||
404 | |||
405 | /* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */ | ||
406 | _GLOBAL(_insw_ns) | ||
407 | cmpwi 0,r5,0 | ||
408 | mtctr r5 | ||
409 | subi r4,r4,2 | ||
410 | blelr- | ||
411 | 00: lhz r5,0(r3) | ||
412 | eieio | ||
413 | sthu r5,2(r4) | ||
414 | bdnz 00b | ||
415 | twi 0,r5,0 | ||
416 | isync | ||
417 | blr | ||
418 | |||
419 | /* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */ | ||
420 | _GLOBAL(_outsw_ns) | ||
421 | cmpwi 0,r5,0 | ||
422 | mtctr r5 | ||
423 | subi r4,r4,2 | ||
424 | blelr- | ||
425 | 00: lhzu r5,2(r4) | ||
426 | sth r5,0(r3) | ||
427 | bdnz 00b | ||
428 | sync | ||
429 | blr | ||
430 | |||
431 | _GLOBAL(_insl_ns) | ||
432 | cmpwi 0,r5,0 | ||
433 | mtctr r5 | ||
434 | subi r4,r4,4 | ||
435 | blelr- | ||
436 | 00: lwz r5,0(r3) | ||
437 | eieio | ||
438 | stwu r5,4(r4) | ||
439 | bdnz 00b | ||
440 | twi 0,r5,0 | ||
441 | isync | ||
442 | blr | ||
443 | |||
444 | _GLOBAL(_outsl_ns) | ||
445 | cmpwi 0,r5,0 | ||
446 | mtctr r5 | ||
447 | subi r4,r4,4 | ||
448 | blelr- | ||
449 | 00: lwzu r5,4(r4) | ||
450 | stw r5,0(r3) | ||
451 | bdnz 00b | ||
452 | sync | ||
453 | blr | ||
454 | |||
455 | /* | ||
456 | * identify_cpu and calls setup_cpu | ||
457 | * In: r3 = base of the cpu_specs array | ||
458 | * r4 = address of cur_cpu_spec | ||
459 | * r5 = relocation offset | ||
460 | */ | ||
461 | _GLOBAL(identify_cpu) | ||
462 | mfpvr r7 | ||
463 | 1: | ||
464 | lwz r8,CPU_SPEC_PVR_MASK(r3) | ||
465 | and r8,r8,r7 | ||
466 | lwz r9,CPU_SPEC_PVR_VALUE(r3) | ||
467 | cmplw 0,r9,r8 | ||
468 | beq 1f | ||
469 | addi r3,r3,CPU_SPEC_ENTRY_SIZE | ||
470 | b 1b | ||
471 | 1: | ||
472 | add r0,r3,r5 | ||
473 | std r0,0(r4) | ||
474 | ld r4,CPU_SPEC_SETUP(r3) | ||
475 | sub r4,r4,r5 | ||
476 | ld r4,0(r4) | ||
477 | sub r4,r4,r5 | ||
478 | mtctr r4 | ||
479 | /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ | ||
480 | mr r4,r3 | ||
481 | mr r3,r5 | ||
482 | bctr | ||
483 | |||
484 | /* | ||
485 | * do_cpu_ftr_fixups - goes through the list of CPU feature fixups | ||
486 | * and writes nop's over sections of code that don't apply for this cpu. | ||
487 | * r3 = data offset (not changed) | ||
488 | */ | ||
489 | _GLOBAL(do_cpu_ftr_fixups) | ||
490 | /* Get CPU 0 features */ | ||
491 | LOADADDR(r6,cur_cpu_spec) | ||
492 | sub r6,r6,r3 | ||
493 | ld r4,0(r6) | ||
494 | sub r4,r4,r3 | ||
495 | ld r4,CPU_SPEC_FEATURES(r4) | ||
496 | /* Get the fixup table */ | ||
497 | LOADADDR(r6,__start___ftr_fixup) | ||
498 | sub r6,r6,r3 | ||
499 | LOADADDR(r7,__stop___ftr_fixup) | ||
500 | sub r7,r7,r3 | ||
501 | /* Do the fixup */ | ||
502 | 1: cmpld r6,r7 | ||
503 | bgelr | ||
504 | addi r6,r6,32 | ||
505 | ld r8,-32(r6) /* mask */ | ||
506 | and r8,r8,r4 | ||
507 | ld r9,-24(r6) /* value */ | ||
508 | cmpld r8,r9 | ||
509 | beq 1b | ||
510 | ld r8,-16(r6) /* section begin */ | ||
511 | ld r9,-8(r6) /* section end */ | ||
512 | subf. r9,r8,r9 | ||
513 | beq 1b | ||
514 | /* write nops over the section of code */ | ||
515 | /* todo: if large section, add a branch at the start of it */ | ||
516 | srwi r9,r9,2 | ||
517 | mtctr r9 | ||
518 | sub r8,r8,r3 | ||
519 | lis r0,0x60000000@h /* nop */ | ||
520 | 3: stw r0,0(r8) | ||
521 | andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l | ||
522 | beq 2f | ||
523 | dcbst 0,r8 /* suboptimal, but simpler */ | ||
524 | sync | ||
525 | icbi 0,r8 | ||
526 | 2: addi r8,r8,4 | ||
527 | bdnz 3b | ||
528 | sync /* additional sync needed on g4 */ | ||
529 | isync | ||
530 | b 1b | ||
531 | |||
532 | #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) | ||
533 | /* | ||
534 | * Do an IO access in real mode | ||
535 | */ | ||
536 | _GLOBAL(real_readb) | ||
537 | mfmsr r7 | ||
538 | ori r0,r7,MSR_DR | ||
539 | xori r0,r0,MSR_DR | ||
540 | sync | ||
541 | mtmsrd r0 | ||
542 | sync | ||
543 | isync | ||
544 | mfspr r6,SPRN_HID4 | ||
545 | rldicl r5,r6,32,0 | ||
546 | ori r5,r5,0x100 | ||
547 | rldicl r5,r5,32,0 | ||
548 | sync | ||
549 | mtspr SPRN_HID4,r5 | ||
550 | isync | ||
551 | slbia | ||
552 | isync | ||
553 | lbz r3,0(r3) | ||
554 | sync | ||
555 | mtspr SPRN_HID4,r6 | ||
556 | isync | ||
557 | slbia | ||
558 | isync | ||
559 | mtmsrd r7 | ||
560 | sync | ||
561 | isync | ||
562 | blr | ||
563 | |||
564 | /* | ||
565 | * Do an IO access in real mode | ||
566 | */ | ||
567 | _GLOBAL(real_writeb) | ||
568 | mfmsr r7 | ||
569 | ori r0,r7,MSR_DR | ||
570 | xori r0,r0,MSR_DR | ||
571 | sync | ||
572 | mtmsrd r0 | ||
573 | sync | ||
574 | isync | ||
575 | mfspr r6,SPRN_HID4 | ||
576 | rldicl r5,r6,32,0 | ||
577 | ori r5,r5,0x100 | ||
578 | rldicl r5,r5,32,0 | ||
579 | sync | ||
580 | mtspr SPRN_HID4,r5 | ||
581 | isync | ||
582 | slbia | ||
583 | isync | ||
584 | stb r3,0(r4) | ||
585 | sync | ||
586 | mtspr SPRN_HID4,r6 | ||
587 | isync | ||
588 | slbia | ||
589 | isync | ||
590 | mtmsrd r7 | ||
591 | sync | ||
592 | isync | ||
593 | blr | ||
594 | #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ | ||
595 | |||
596 | /* | ||
597 | * SCOM access functions for 970 (FX only for now) | ||
598 | * | ||
599 | * unsigned long scom970_read(unsigned int address); | ||
600 | * void scom970_write(unsigned int address, unsigned long value); | ||
601 | * | ||
602 | * The address passed in is the 24 bits register address. This code | ||
603 | * is 970 specific and will not check the status bits, so you should | ||
604 | * know what you are doing. | ||
605 | */ | ||
606 | _GLOBAL(scom970_read) | ||
607 | /* interrupts off */ | ||
608 | mfmsr r4 | ||
609 | ori r0,r4,MSR_EE | ||
610 | xori r0,r0,MSR_EE | ||
611 | mtmsrd r0,1 | ||
612 | |||
613 | /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits | ||
614 | * (including parity). On current CPUs they must be 0'd, | ||
615 | * and finally or in RW bit | ||
616 | */ | ||
617 | rlwinm r3,r3,8,0,15 | ||
618 | ori r3,r3,0x8000 | ||
619 | |||
620 | /* do the actual scom read */ | ||
621 | sync | ||
622 | mtspr SPRN_SCOMC,r3 | ||
623 | isync | ||
624 | mfspr r3,SPRN_SCOMD | ||
625 | isync | ||
626 | mfspr r0,SPRN_SCOMC | ||
627 | isync | ||
628 | |||
629 | /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah | ||
630 | * that's the best we can do). Not implemented yet as we don't use | ||
631 | * the scom on any of the bogus CPUs yet, but may have to be done | ||
632 | * ultimately | ||
633 | */ | ||
634 | |||
635 | /* restore interrupts */ | ||
636 | mtmsrd r4,1 | ||
637 | blr | ||
638 | |||
639 | |||
640 | _GLOBAL(scom970_write) | ||
641 | /* interrupts off */ | ||
642 | mfmsr r5 | ||
643 | ori r0,r5,MSR_EE | ||
644 | xori r0,r0,MSR_EE | ||
645 | mtmsrd r0,1 | ||
646 | |||
647 | /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits | ||
648 | * (including parity). On current CPUs they must be 0'd. | ||
649 | */ | ||
650 | |||
651 | rlwinm r3,r3,8,0,15 | ||
652 | |||
653 | sync | ||
654 | mtspr SPRN_SCOMD,r4 /* write data */ | ||
655 | isync | ||
656 | mtspr SPRN_SCOMC,r3 /* write command */ | ||
657 | isync | ||
658 | mfspr 3,SPRN_SCOMC | ||
659 | isync | ||
660 | |||
661 | /* restore interrupts */ | ||
662 | mtmsrd r5,1 | ||
663 | blr | ||
664 | |||
665 | |||
666 | /* | ||
667 | * Create a kernel thread | ||
668 | * kernel_thread(fn, arg, flags) | ||
669 | */ | ||
670 | _GLOBAL(kernel_thread) | ||
671 | std r29,-24(r1) | ||
672 | std r30,-16(r1) | ||
673 | stdu r1,-STACK_FRAME_OVERHEAD(r1) | ||
674 | mr r29,r3 | ||
675 | mr r30,r4 | ||
676 | ori r3,r5,CLONE_VM /* flags */ | ||
677 | oris r3,r3,(CLONE_UNTRACED>>16) | ||
678 | li r4,0 /* new sp (unused) */ | ||
679 | li r0,__NR_clone | ||
680 | sc | ||
681 | cmpdi 0,r3,0 /* parent or child? */ | ||
682 | bne 1f /* return if parent */ | ||
683 | li r0,0 | ||
684 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | ||
685 | ld r2,8(r29) | ||
686 | ld r29,0(r29) | ||
687 | mtlr r29 /* fn addr in lr */ | ||
688 | mr r3,r30 /* load arg and call fn */ | ||
689 | blrl | ||
690 | li r0,__NR_exit /* exit after child exits */ | ||
691 | li r3,0 | ||
692 | sc | ||
693 | 1: addi r1,r1,STACK_FRAME_OVERHEAD | ||
694 | ld r29,-24(r1) | ||
695 | ld r30,-16(r1) | ||
696 | blr | ||
697 | |||
698 | /* | ||
699 | * disable_kernel_fp() | ||
700 | * Disable the FPU. | ||
701 | */ | ||
702 | _GLOBAL(disable_kernel_fp) | ||
703 | mfmsr r3 | ||
704 | rldicl r0,r3,(63-MSR_FP_LG),1 | ||
705 | rldicl r3,r0,(MSR_FP_LG+1),0 | ||
706 | mtmsrd r3 /* disable use of fpu now */ | ||
707 | isync | ||
708 | blr | ||
709 | |||
710 | #ifdef CONFIG_ALTIVEC | ||
711 | |||
712 | #if 0 /* this has no callers for now */ | ||
713 | /* | ||
714 | * disable_kernel_altivec() | ||
715 | * Disable the VMX. | ||
716 | */ | ||
717 | _GLOBAL(disable_kernel_altivec) | ||
718 | mfmsr r3 | ||
719 | rldicl r0,r3,(63-MSR_VEC_LG),1 | ||
720 | rldicl r3,r0,(MSR_VEC_LG+1),0 | ||
721 | mtmsrd r3 /* disable use of VMX now */ | ||
722 | isync | ||
723 | blr | ||
724 | #endif /* 0 */ | ||
725 | |||
726 | /* | ||
727 | * giveup_altivec(tsk) | ||
728 | * Disable VMX for the task given as the argument, | ||
729 | * and save the vector registers in its thread_struct. | ||
730 | * Enables the VMX for use in the kernel on return. | ||
731 | */ | ||
732 | _GLOBAL(giveup_altivec) | ||
733 | mfmsr r5 | ||
734 | oris r5,r5,MSR_VEC@h | ||
735 | mtmsrd r5 /* enable use of VMX now */ | ||
736 | isync | ||
737 | cmpdi 0,r3,0 | ||
738 | beqlr- /* if no previous owner, done */ | ||
739 | addi r3,r3,THREAD /* want THREAD of task */ | ||
740 | ld r5,PT_REGS(r3) | ||
741 | cmpdi 0,r5,0 | ||
742 | SAVE_32VRS(0,r4,r3) | ||
743 | mfvscr vr0 | ||
744 | li r4,THREAD_VSCR | ||
745 | stvx vr0,r4,r3 | ||
746 | beq 1f | ||
747 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
748 | lis r3,MSR_VEC@h | ||
749 | andc r4,r4,r3 /* disable FP for previous task */ | ||
750 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
751 | 1: | ||
752 | #ifndef CONFIG_SMP | ||
753 | li r5,0 | ||
754 | ld r4,last_task_used_altivec@got(r2) | ||
755 | std r5,0(r4) | ||
756 | #endif /* CONFIG_SMP */ | ||
757 | blr | ||
758 | |||
759 | #endif /* CONFIG_ALTIVEC */ | ||
760 | |||
761 | _GLOBAL(__setup_cpu_power3) | ||
762 | blr | ||
763 | |||
764 | _GLOBAL(execve) | ||
765 | li r0,__NR_execve | ||
766 | sc | ||
767 | bnslr | ||
768 | neg r3,r3 | ||
769 | blr | ||
770 | |||
771 | /* kexec_wait(phys_cpu) | ||
772 | * | ||
773 | * wait for the flag to change, indicating this kernel is going away but | ||
774 | * the slave code for the next one is at addresses 0 to 100. | ||
775 | * | ||
776 | * This is used by all slaves. | ||
777 | * | ||
778 | * Physical (hardware) cpu id should be in r3. | ||
779 | */ | ||
780 | _GLOBAL(kexec_wait) | ||
781 | bl 1f | ||
782 | 1: mflr r5 | ||
783 | addi r5,r5,kexec_flag-1b | ||
784 | |||
785 | 99: HMT_LOW | ||
786 | #ifdef CONFIG_KEXEC /* use no memory without kexec */ | ||
787 | lwz r4,0(r5) | ||
788 | cmpwi 0,r4,0 | ||
789 | bnea 0x60 | ||
790 | #endif | ||
791 | b 99b | ||
792 | |||
793 | /* this can be in text because we won't change it until we are | ||
794 | * running in real anyways | ||
795 | */ | ||
796 | kexec_flag: | ||
797 | .long 0 | ||
798 | |||
799 | |||
800 | #ifdef CONFIG_KEXEC | ||
801 | |||
802 | /* kexec_smp_wait(void) | ||
803 | * | ||
804 | * call with interrupts off | ||
805 | * note: this is a terminal routine, it does not save lr | ||
806 | * | ||
807 | * get phys id from paca | ||
808 | * set paca id to -1 to say we got here | ||
809 | * switch to real mode | ||
810 | * join other cpus in kexec_wait(phys_id) | ||
811 | */ | ||
812 | _GLOBAL(kexec_smp_wait) | ||
813 | lhz r3,PACAHWCPUID(r13) | ||
814 | li r4,-1 | ||
815 | sth r4,PACAHWCPUID(r13) /* let others know we left */ | ||
816 | bl real_mode | ||
817 | b .kexec_wait | ||
818 | |||
819 | /* | ||
820 | * switch to real mode (turn mmu off) | ||
821 | * we use the early kernel trick that the hardware ignores bits | ||
822 | * 0 and 1 (big endian) of the effective address in real mode | ||
823 | * | ||
824 | * don't overwrite r3 here, it is live for kexec_wait above. | ||
825 | */ | ||
826 | real_mode: /* assume normal blr return */ | ||
827 | 1: li r9,MSR_RI | ||
828 | li r10,MSR_DR|MSR_IR | ||
829 | mflr r11 /* return address to SRR0 */ | ||
830 | mfmsr r12 | ||
831 | andc r9,r12,r9 | ||
832 | andc r10,r12,r10 | ||
833 | |||
834 | mtmsrd r9,1 | ||
835 | mtspr SPRN_SRR1,r10 | ||
836 | mtspr SPRN_SRR0,r11 | ||
837 | rfid | ||
838 | |||
839 | |||
840 | /* | ||
841 | * kexec_sequence(newstack, start, image, control, clear_all()) | ||
842 | * | ||
843 | * does the grungy work with stack switching and real mode switches | ||
844 | * also does simple calls to other code | ||
845 | */ | ||
846 | |||
847 | _GLOBAL(kexec_sequence) | ||
848 | mflr r0 | ||
849 | std r0,16(r1) | ||
850 | |||
851 | /* switch stacks to newstack -- &kexec_stack.stack */ | ||
852 | stdu r1,THREAD_SIZE-112(r3) | ||
853 | mr r1,r3 | ||
854 | |||
855 | li r0,0 | ||
856 | std r0,16(r1) | ||
857 | |||
858 | /* save regs for local vars on new stack. | ||
859 | * yes, we won't go back, but ... | ||
860 | */ | ||
861 | std r31,-8(r1) | ||
862 | std r30,-16(r1) | ||
863 | std r29,-24(r1) | ||
864 | std r28,-32(r1) | ||
865 | std r27,-40(r1) | ||
866 | std r26,-48(r1) | ||
867 | std r25,-56(r1) | ||
868 | |||
869 | stdu r1,-112-64(r1) | ||
870 | |||
871 | /* save args into preserved regs */ | ||
872 | mr r31,r3 /* newstack (both) */ | ||
873 | mr r30,r4 /* start (real) */ | ||
874 | mr r29,r5 /* image (virt) */ | ||
875 | mr r28,r6 /* control, unused */ | ||
876 | mr r27,r7 /* clear_all() fn desc */ | ||
877 | mr r26,r8 /* spare */ | ||
878 | lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ | ||
879 | |||
880 | /* disable interrupts, we are overwriting kernel data next */ | ||
881 | mfmsr r3 | ||
882 | rlwinm r3,r3,0,17,15 | ||
883 | mtmsrd r3,1 | ||
884 | |||
885 | /* copy dest pages, flush whole dest image */ | ||
886 | mr r3,r29 | ||
887 | bl .kexec_copy_flush /* (image) */ | ||
888 | |||
889 | /* turn off mmu */ | ||
890 | bl real_mode | ||
891 | |||
892 | /* clear out hardware hash page table and tlb */ | ||
893 | ld r5,0(r27) /* deref function descriptor */ | ||
894 | mtctr r5 | ||
895 | bctrl /* ppc_md.hash_clear_all(void); */ | ||
896 | |||
897 | /* | ||
898 | * kexec image calling is: | ||
899 | * the first 0x100 bytes of the entry point are copied to 0 | ||
900 | * | ||
901 | * all slaves branch to slave = 0x60 (absolute) | ||
902 | * slave(phys_cpu_id); | ||
903 | * | ||
904 | * master goes to start = entry point | ||
905 | * start(phys_cpu_id, start, 0); | ||
906 | * | ||
907 | * | ||
908 | * a wrapper is needed to call existing kernels, here is an approximate | ||
909 | * description of one method: | ||
910 | * | ||
911 | * v2: (2.6.10) | ||
912 | * start will be near the boot_block (maybe 0x100 bytes before it?) | ||
913 | * it will have a 0x60, which will b to boot_block, where it will wait | ||
914 | * and 0 will store phys into struct boot-block and load r3 from there, | ||
915 | * copy kernel 0-0x100 and tell slaves to back down to 0x60 again | ||
916 | * | ||
917 | * v1: (2.6.9) | ||
918 | * boot block will have all cpus scanning device tree to see if they | ||
919 | * are the boot cpu ????? | ||
920 | * other device tree differences (prop sizes, va vs pa, etc)... | ||
921 | */ | ||
922 | |||
923 | /* copy 0x100 bytes starting at start to 0 */ | ||
924 | li r3,0 | ||
925 | mr r4,r30 | ||
926 | li r5,0x100 | ||
927 | li r6,0 | ||
928 | bl .copy_and_flush /* (dest, src, copy limit, start offset) */ | ||
929 | 1: /* assume normal blr return */ | ||
930 | |||
931 | /* release other cpus to the new kernel secondary start at 0x60 */ | ||
932 | mflr r5 | ||
933 | li r6,1 | ||
934 | stw r6,kexec_flag-1b(5) | ||
935 | mr r3,r25 # my phys cpu | ||
936 | mr r4,r30 # start, aka phys mem offset | ||
937 | mtlr 4 | ||
938 | li r5,0 | ||
939 | blr /* image->start(physid, image->start, 0); */ | ||
940 | #endif /* CONFIG_KEXEC */ | ||