blob: e0c850d85c530b933515a123bf66fb42d81ebed2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * This file contains miscellaneous low-level functions.
3 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
4 *
5 * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
6 * and Paul Mackerras.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/sys.h>
16#include <asm/unistd.h>
17#include <asm/errno.h>
18#include <asm/processor.h>
19#include <asm/page.h>
20#include <asm/cache.h>
21#include <asm/cputable.h>
22#include <asm/mmu.h>
23#include <asm/ppc_asm.h>
24#include <asm/thread_info.h>
Sam Ravnborg0013a852005-09-09 20:57:26 +020025#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Marcelo Tosatti55b63322005-11-05 14:06:24 -020027#ifdef CONFIG_8xx
28#define ISYNC_8xx isync
29#else
30#define ISYNC_8xx
31#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 .text
33
34 .align 5
35_GLOBAL(__delay)
36 cmpwi 0,r3,0
37 mtctr r3
38 beqlr
391: bdnz 1b
40 blr
41
42/*
43 * Returns (address we're running at) - (address we were linked at)
44 * for use before the text and data are mapped to KERNELBASE.
45 */
46_GLOBAL(reloc_offset)
47 mflr r0
48 bl 1f
491: mflr r3
50 lis r4,1b@ha
51 addi r4,r4,1b@l
52 subf r3,r4,r3
53 mtlr r0
54 blr
55
56/*
57 * add_reloc_offset(x) returns x + reloc_offset().
58 */
59_GLOBAL(add_reloc_offset)
60 mflr r0
61 bl 1f
621: mflr r5
63 lis r4,1b@ha
64 addi r4,r4,1b@l
65 subf r5,r4,r5
66 add r3,r3,r5
67 mtlr r0
68 blr
69
70/*
71 * sub_reloc_offset(x) returns x - reloc_offset().
72 */
73_GLOBAL(sub_reloc_offset)
74 mflr r0
75 bl 1f
761: mflr r5
77 lis r4,1b@ha
78 addi r4,r4,1b@l
79 subf r5,r4,r5
80 subf r3,r5,r3
81 mtlr r0
82 blr
83
84/*
85 * reloc_got2 runs through the .got2 section adding an offset
86 * to each entry.
87 */
88_GLOBAL(reloc_got2)
89 mflr r11
90 lis r7,__got2_start@ha
91 addi r7,r7,__got2_start@l
92 lis r8,__got2_end@ha
93 addi r8,r8,__got2_end@l
94 subf r8,r7,r8
95 srwi. r8,r8,2
96 beqlr
97 mtctr r8
98 bl 1f
991: mflr r0
100 lis r4,1b@ha
101 addi r4,r4,1b@l
102 subf r0,r4,r0
103 add r7,r0,r7
1042: lwz r0,0(r7)
105 add r0,r0,r3
106 stw r0,0(r7)
107 addi r7,r7,4
108 bdnz 2b
109 mtlr r11
110 blr
111
112/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 * call_setup_cpu - call the setup_cpu function for this cpu
114 * r3 = data offset, r24 = cpu number
115 *
116 * Setup function is called with:
117 * r3 = data offset
Kumar Gala400d2212005-09-27 15:13:12 -0500118 * r4 = ptr to CPU spec (relocated)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 */
120_GLOBAL(call_setup_cpu)
Kumar Gala400d2212005-09-27 15:13:12 -0500121 addis r4,r3,cur_cpu_spec@ha
122 addi r4,r4,cur_cpu_spec@l
123 lwz r4,0(r4)
124 add r4,r4,r3
125 lwz r5,CPU_SPEC_SETUP(r4)
126 cmpi 0,r5,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 add r5,r5,r3
Kumar Gala400d2212005-09-27 15:13:12 -0500128 beqlr
129 mtctr r5
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 bctr
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/*
133 * complement mask on the msr then "or" some values on.
134 * _nmask_and_or_msr(nmask, value_to_or)
135 */
136_GLOBAL(_nmask_and_or_msr)
137 mfmsr r0 /* Get current msr */
138 andc r0,r0,r3 /* And off the bits set in r3 (first parm) */
139 or r0,r0,r4 /* Or on the bits in r4 (second parm) */
140 SYNC /* Some chip revs have problems here... */
141 mtmsr r0 /* Update machine state */
142 isync
143 blr /* Done */
144
145
146/*
147 * Flush MMU TLB
148 */
149_GLOBAL(_tlbia)
150#if defined(CONFIG_40x)
151 sync /* Flush to memory before changing mapping */
152 tlbia
153 isync /* Flush shadow TLB */
154#elif defined(CONFIG_44x)
155 li r3,0
156 sync
157
158 /* Load high watermark */
159 lis r4,tlb_44x_hwater@ha
160 lwz r5,tlb_44x_hwater@l(r4)
161
1621: tlbwe r3,r3,PPC44x_TLB_PAGEID
163 addi r3,r3,1
164 cmpw 0,r3,r5
165 ble 1b
166
167 isync
168#elif defined(CONFIG_FSL_BOOKE)
169 /* Invalidate all entries in TLB0 */
170 li r3, 0x04
171 tlbivax 0,3
172 /* Invalidate all entries in TLB1 */
173 li r3, 0x0c
174 tlbivax 0,3
175 /* Invalidate all entries in TLB2 */
176 li r3, 0x14
177 tlbivax 0,3
178 /* Invalidate all entries in TLB3 */
179 li r3, 0x1c
180 tlbivax 0,3
181 msync
182#ifdef CONFIG_SMP
183 tlbsync
184#endif /* CONFIG_SMP */
185#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
186#if defined(CONFIG_SMP)
187 rlwinm r8,r1,0,0,18
188 lwz r8,TI_CPU(r8)
189 oris r8,r8,10
190 mfmsr r10
191 SYNC
192 rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
193 rlwinm r0,r0,0,28,26 /* clear DR */
194 mtmsr r0
195 SYNC_601
196 isync
197 lis r9,mmu_hash_lock@h
198 ori r9,r9,mmu_hash_lock@l
199 tophys(r9,r9)
20010: lwarx r7,0,r9
201 cmpwi 0,r7,0
202 bne- 10b
203 stwcx. r8,0,r9
204 bne- 10b
205 sync
206 tlbia
207 sync
208 TLBSYNC
209 li r0,0
210 stw r0,0(r9) /* clear mmu_hash_lock */
211 mtmsr r10
212 SYNC_601
213 isync
214#else /* CONFIG_SMP */
215 sync
216 tlbia
217 sync
218#endif /* CONFIG_SMP */
219#endif /* ! defined(CONFIG_40x) */
220 blr
221
222/*
223 * Flush MMU TLB for a particular address
224 */
225_GLOBAL(_tlbie)
226#if defined(CONFIG_40x)
Benjamin Herrenschmidte701d262007-10-30 09:46:06 +1100227 /* We run the search with interrupts disabled because we have to change
228 * the PID and I don't want to preempt when that happens.
229 */
230 mfmsr r5
231 mfspr r6,SPRN_PID
232 wrteei 0
233 mtspr SPRN_PID,r4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 tlbsx. r3, 0, r3
Benjamin Herrenschmidte701d262007-10-30 09:46:06 +1100235 mtspr SPRN_PID,r6
236 wrtee r5
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 bne 10f
238 sync
239 /* There are only 64 TLB entries, so r3 < 64, which means bit 25 is clear.
240 * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate
241 * the TLB entry. */
242 tlbwe r3, r3, TLB_TAG
243 isync
24410:
245#elif defined(CONFIG_44x)
Benjamin Herrenschmidte701d262007-10-30 09:46:06 +1100246 mfspr r5,SPRN_MMUCR
247 rlwimi r5,r4,0,24,31 /* Set TID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
David Gibsonaa1cf632007-08-07 14:20:50 +1000249 /* We have to run the search with interrupts disabled, even critical
250 * and debug interrupts (in fact the only critical exceptions we have
251 * are debug and machine check). Otherwise an interrupt which causes
252 * a TLB miss can clobber the MMUCR between the mtspr and the tlbsx. */
Benjamin Herrenschmidte701d262007-10-30 09:46:06 +1100253 mfmsr r4
David Gibsonaa1cf632007-08-07 14:20:50 +1000254 lis r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@ha
255 addi r6,r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l
Benjamin Herrenschmidte701d262007-10-30 09:46:06 +1100256 andc r6,r4,r6
David Gibsonaa1cf632007-08-07 14:20:50 +1000257 mtmsr r6
Benjamin Herrenschmidte701d262007-10-30 09:46:06 +1100258 mtspr SPRN_MMUCR,r5
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 tlbsx. r3, 0, r3
Benjamin Herrenschmidte701d262007-10-30 09:46:06 +1100260 mtmsr r4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 bne 10f
262 sync
263 /* There are only 64 TLB entries, so r3 < 64,
264 * which means bit 22, is clear. Since 22 is
265 * the V bit in the TLB_PAGEID, loading this
266 * value will invalidate the TLB entry.
267 */
268 tlbwe r3, r3, PPC44x_TLB_PAGEID
269 isync
27010:
271#elif defined(CONFIG_FSL_BOOKE)
272 rlwinm r4, r3, 0, 0, 19
273 ori r5, r4, 0x08 /* TLBSEL = 1 */
274 ori r6, r4, 0x10 /* TLBSEL = 2 */
275 ori r7, r4, 0x18 /* TLBSEL = 3 */
276 tlbivax 0, r4
277 tlbivax 0, r5
278 tlbivax 0, r6
279 tlbivax 0, r7
280 msync
281#if defined(CONFIG_SMP)
282 tlbsync
283#endif /* CONFIG_SMP */
284#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
285#if defined(CONFIG_SMP)
286 rlwinm r8,r1,0,0,18
287 lwz r8,TI_CPU(r8)
288 oris r8,r8,11
289 mfmsr r10
290 SYNC
291 rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
292 rlwinm r0,r0,0,28,26 /* clear DR */
293 mtmsr r0
294 SYNC_601
295 isync
296 lis r9,mmu_hash_lock@h
297 ori r9,r9,mmu_hash_lock@l
298 tophys(r9,r9)
29910: lwarx r7,0,r9
300 cmpwi 0,r7,0
301 bne- 10b
302 stwcx. r8,0,r9
303 bne- 10b
304 eieio
305 tlbie r3
306 sync
307 TLBSYNC
308 li r0,0
309 stw r0,0(r9) /* clear mmu_hash_lock */
310 mtmsr r10
311 SYNC_601
312 isync
313#else /* CONFIG_SMP */
314 tlbie r3
315 sync
316#endif /* CONFIG_SMP */
317#endif /* ! CONFIG_40x */
318 blr
319
320/*
321 * Flush instruction cache.
322 * This is a no-op on the 601.
323 */
324_GLOBAL(flush_instruction_cache)
325#if defined(CONFIG_8xx)
326 isync
327 lis r5, IDC_INVALL@h
328 mtspr SPRN_IC_CST, r5
329#elif defined(CONFIG_4xx)
330#ifdef CONFIG_403GCX
331 li r3, 512
332 mtctr r3
333 lis r4, KERNELBASE@h
3341: iccci 0, r4
335 addi r4, r4, 16
336 bdnz 1b
337#else
338 lis r3, KERNELBASE@h
339 iccci 0,r3
340#endif
341#elif CONFIG_FSL_BOOKE
Kumar Gala33d9e9b2005-06-25 14:54:37 -0700342BEGIN_FTR_SECTION
343 mfspr r3,SPRN_L1CSR0
344 ori r3,r3,L1CSR0_CFI|L1CSR0_CLFC
345 /* msync; isync recommended here */
346 mtspr SPRN_L1CSR0,r3
347 isync
348 blr
David Gibson4508dc22007-06-13 14:52:57 +1000349END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 mfspr r3,SPRN_L1CSR1
351 ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
352 mtspr SPRN_L1CSR1,r3
353#else
354 mfspr r3,SPRN_PVR
355 rlwinm r3,r3,16,16,31
356 cmpwi 0,r3,1
357 beqlr /* for 601, do nothing */
358 /* 603/604 processor - use invalidate-all bit in HID0 */
359 mfspr r3,SPRN_HID0
360 ori r3,r3,HID0_ICFI
361 mtspr SPRN_HID0,r3
362#endif /* CONFIG_8xx/4xx */
363 isync
364 blr
365
366/*
367 * Write any modified data cache blocks out to memory
368 * and invalidate the corresponding instruction cache blocks.
369 * This is a no-op on the 601.
370 *
David Gibson26ef5c02005-11-10 11:50:16 +1100371 * __flush_icache_range(unsigned long start, unsigned long stop)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 */
David Gibson26ef5c02005-11-10 11:50:16 +1100373_GLOBAL(__flush_icache_range)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374BEGIN_FTR_SECTION
375 blr /* for 601, do nothing */
David Gibson4508dc22007-06-13 14:52:57 +1000376END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000377 li r5,L1_CACHE_BYTES-1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 andc r3,r3,r5
379 subf r4,r3,r4
380 add r4,r4,r5
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000381 srwi. r4,r4,L1_CACHE_SHIFT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 beqlr
383 mtctr r4
384 mr r6,r3
3851: dcbst 0,r3
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000386 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 bdnz 1b
388 sync /* wait for dcbst's to get to ram */
389 mtctr r4
3902: icbi 0,r6
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000391 addi r6,r6,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 bdnz 2b
393 sync /* additional sync needed on g4 */
394 isync
395 blr
396/*
397 * Write any modified data cache blocks out to memory.
398 * Does not invalidate the corresponding cache lines (especially for
399 * any corresponding instruction cache).
400 *
401 * clean_dcache_range(unsigned long start, unsigned long stop)
402 */
403_GLOBAL(clean_dcache_range)
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000404 li r5,L1_CACHE_BYTES-1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 andc r3,r3,r5
406 subf r4,r3,r4
407 add r4,r4,r5
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000408 srwi. r4,r4,L1_CACHE_SHIFT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 beqlr
410 mtctr r4
411
4121: dcbst 0,r3
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000413 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 bdnz 1b
415 sync /* wait for dcbst's to get to ram */
416 blr
417
418/*
419 * Write any modified data cache blocks out to memory and invalidate them.
420 * Does not invalidate the corresponding instruction cache blocks.
421 *
422 * flush_dcache_range(unsigned long start, unsigned long stop)
423 */
424_GLOBAL(flush_dcache_range)
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000425 li r5,L1_CACHE_BYTES-1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 andc r3,r3,r5
427 subf r4,r3,r4
428 add r4,r4,r5
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000429 srwi. r4,r4,L1_CACHE_SHIFT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 beqlr
431 mtctr r4
432
4331: dcbf 0,r3
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000434 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 bdnz 1b
436 sync /* wait for dcbst's to get to ram */
437 blr
438
439/*
440 * Like above, but invalidate the D-cache. This is used by the 8xx
441 * to invalidate the cache so the PPC core doesn't get stale data
442 * from the CPM (no cache snooping here :-).
443 *
444 * invalidate_dcache_range(unsigned long start, unsigned long stop)
445 */
446_GLOBAL(invalidate_dcache_range)
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000447 li r5,L1_CACHE_BYTES-1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 andc r3,r3,r5
449 subf r4,r3,r4
450 add r4,r4,r5
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000451 srwi. r4,r4,L1_CACHE_SHIFT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 beqlr
453 mtctr r4
454
4551: dcbi 0,r3
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000456 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 bdnz 1b
458 sync /* wait for dcbi's to get to ram */
459 blr
460
461#ifdef CONFIG_NOT_COHERENT_CACHE
462/*
463 * 40x cores have 8K or 16K dcache and 32 byte line size.
464 * 44x has a 32K dcache and 32 byte line size.
465 * 8xx has 1, 2, 4, 8K variants.
466 * For now, cover the worst case of the 44x.
467 * Must be called with external interrupts disabled.
468 */
469#define CACHE_NWAYS 64
470#define CACHE_NLINES 16
471
472_GLOBAL(flush_dcache_all)
473 li r4, (2 * CACHE_NWAYS * CACHE_NLINES)
474 mtctr r4
475 lis r5, KERNELBASE@h
4761: lwz r3, 0(r5) /* Load one word from every line */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000477 addi r5, r5, L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 bdnz 1b
479 blr
480#endif /* CONFIG_NOT_COHERENT_CACHE */
481
482/*
483 * Flush a particular page from the data cache to RAM.
484 * Note: this is necessary because the instruction cache does *not*
485 * snoop from the data cache.
486 * This is a no-op on the 601 which has a unified cache.
487 *
488 * void __flush_dcache_icache(void *page)
489 */
490_GLOBAL(__flush_dcache_icache)
491BEGIN_FTR_SECTION
492 blr /* for 601, do nothing */
David Gibson4508dc22007-06-13 14:52:57 +1000493END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 rlwinm r3,r3,0,0,19 /* Get page base address */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000495 li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 mtctr r4
497 mr r6,r3
4980: dcbst 0,r3 /* Write line to ram */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000499 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 bdnz 0b
501 sync
Benjamin Herrenschmidtb98ac052007-10-31 16:42:19 +1100502#ifndef CONFIG_44x
503 /* We don't flush the icache on 44x. Those have a virtual icache
504 * and we don't have access to the virtual address here (it's
505 * not the page vaddr but where it's mapped in user space). The
506 * flushing of the icache on these is handled elsewhere, when
507 * a change in the address space occurs, before returning to
508 * user space
509 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 mtctr r4
5111: icbi 0,r6
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000512 addi r6,r6,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 bdnz 1b
514 sync
515 isync
Benjamin Herrenschmidtb98ac052007-10-31 16:42:19 +1100516#endif /* CONFIG_44x */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 blr
518
519/*
520 * Flush a particular page from the data cache to RAM, identified
521 * by its physical address. We turn off the MMU so we can just use
522 * the physical address (this may be a highmem page without a kernel
523 * mapping).
524 *
525 * void __flush_dcache_icache_phys(unsigned long physaddr)
526 */
527_GLOBAL(__flush_dcache_icache_phys)
528BEGIN_FTR_SECTION
529 blr /* for 601, do nothing */
David Gibson4508dc22007-06-13 14:52:57 +1000530END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 mfmsr r10
532 rlwinm r0,r10,0,28,26 /* clear DR */
533 mtmsr r0
534 isync
535 rlwinm r3,r3,0,0,19 /* Get page base address */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000536 li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 mtctr r4
538 mr r6,r3
5390: dcbst 0,r3 /* Write line to ram */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000540 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 bdnz 0b
542 sync
543 mtctr r4
5441: icbi 0,r6
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000545 addi r6,r6,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 bdnz 1b
547 sync
548 mtmsr r10 /* restore DR */
549 isync
550 blr
551
552/*
553 * Clear pages using the dcbz instruction, which doesn't cause any
554 * memory traffic (except to write out any cache lines which get
555 * displaced). This only works on cacheable memory.
556 *
557 * void clear_pages(void *page, int order) ;
558 */
559_GLOBAL(clear_pages)
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000560 li r0,4096/L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 slw r0,r0,r4
562 mtctr r0
563#ifdef CONFIG_8xx
564 li r4, 0
5651: stw r4, 0(r3)
566 stw r4, 4(r3)
567 stw r4, 8(r3)
568 stw r4, 12(r3)
569#else
5701: dcbz 0,r3
571#endif
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000572 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 bdnz 1b
574 blr
575
576/*
577 * Copy a whole page. We use the dcbz instruction on the destination
578 * to reduce memory traffic (it eliminates the unnecessary reads of
579 * the destination into cache). This requires that the destination
580 * is cacheable.
581 */
582#define COPY_16_BYTES \
583 lwz r6,4(r4); \
584 lwz r7,8(r4); \
585 lwz r8,12(r4); \
586 lwzu r9,16(r4); \
587 stw r6,4(r3); \
588 stw r7,8(r3); \
589 stw r8,12(r3); \
590 stwu r9,16(r3)
591
592_GLOBAL(copy_page)
593 addi r3,r3,-4
594 addi r4,r4,-4
595
596#ifdef CONFIG_8xx
597 /* don't use prefetch on 8xx */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000598 li r0,4096/L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 mtctr r0
6001: COPY_16_BYTES
601 bdnz 1b
602 blr
603
604#else /* not 8xx, we can prefetch */
605 li r5,4
606
607#if MAX_COPY_PREFETCH > 1
608 li r0,MAX_COPY_PREFETCH
609 li r11,4
610 mtctr r0
61111: dcbt r11,r4
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000612 addi r11,r11,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 bdnz 11b
614#else /* MAX_COPY_PREFETCH == 1 */
615 dcbt r5,r4
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000616 li r11,L1_CACHE_BYTES+4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617#endif /* MAX_COPY_PREFETCH */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000618 li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 crclr 4*cr0+eq
6202:
621 mtctr r0
6221:
623 dcbt r11,r4
624 dcbz r5,r3
625 COPY_16_BYTES
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000626#if L1_CACHE_BYTES >= 32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 COPY_16_BYTES
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000628#if L1_CACHE_BYTES >= 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 COPY_16_BYTES
630 COPY_16_BYTES
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000631#if L1_CACHE_BYTES >= 128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 COPY_16_BYTES
633 COPY_16_BYTES
634 COPY_16_BYTES
635 COPY_16_BYTES
636#endif
637#endif
638#endif
639 bdnz 1b
640 beqlr
641 crnot 4*cr0+eq,4*cr0+eq
642 li r0,MAX_COPY_PREFETCH
643 li r11,4
644 b 2b
645#endif /* CONFIG_8xx */
646
647/*
648 * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
649 * void atomic_set_mask(atomic_t mask, atomic_t *addr);
650 */
651_GLOBAL(atomic_clear_mask)
65210: lwarx r5,0,r4
653 andc r5,r5,r3
654 PPC405_ERR77(0,r4)
655 stwcx. r5,0,r4
656 bne- 10b
657 blr
658_GLOBAL(atomic_set_mask)
65910: lwarx r5,0,r4
660 or r5,r5,r3
661 PPC405_ERR77(0,r4)
662 stwcx. r5,0,r4
663 bne- 10b
664 blr
665
666/*
667 * I/O string operations
668 *
669 * insb(port, buf, len)
670 * outsb(port, buf, len)
671 * insw(port, buf, len)
672 * outsw(port, buf, len)
673 * insl(port, buf, len)
674 * outsl(port, buf, len)
675 * insw_ns(port, buf, len)
676 * outsw_ns(port, buf, len)
677 * insl_ns(port, buf, len)
678 * outsl_ns(port, buf, len)
679 *
680 * The *_ns versions don't do byte-swapping.
681 */
682_GLOBAL(_insb)
683 cmpwi 0,r5,0
684 mtctr r5
685 subi r4,r4,1
686 blelr-
68700: lbz r5,0(r3)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020068801: eieio
68902: stbu r5,1(r4)
690 ISYNC_8xx
691 .section .fixup,"ax"
69203: blr
693 .text
694 .section __ex_table, "a"
695 .align 2
696 .long 00b, 03b
697 .long 01b, 03b
698 .long 02b, 03b
699 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 bdnz 00b
701 blr
702
703_GLOBAL(_outsb)
704 cmpwi 0,r5,0
705 mtctr r5
706 subi r4,r4,1
707 blelr-
70800: lbzu r5,1(r4)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020070901: stb r5,0(r3)
71002: eieio
711 ISYNC_8xx
712 .section .fixup,"ax"
71303: blr
714 .text
715 .section __ex_table, "a"
716 .align 2
717 .long 00b, 03b
718 .long 01b, 03b
719 .long 02b, 03b
720 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 bdnz 00b
722 blr
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724_GLOBAL(_insw_ns)
725 cmpwi 0,r5,0
726 mtctr r5
727 subi r4,r4,2
728 blelr-
72900: lhz r5,0(r3)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020073001: eieio
73102: sthu r5,2(r4)
732 ISYNC_8xx
733 .section .fixup,"ax"
73403: blr
735 .text
736 .section __ex_table, "a"
737 .align 2
738 .long 00b, 03b
739 .long 01b, 03b
740 .long 02b, 03b
741 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 bdnz 00b
743 blr
744
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745_GLOBAL(_outsw_ns)
746 cmpwi 0,r5,0
747 mtctr r5
748 subi r4,r4,2
749 blelr-
75000: lhzu r5,2(r4)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020075101: sth r5,0(r3)
75202: eieio
753 ISYNC_8xx
754 .section .fixup,"ax"
75503: blr
756 .text
757 .section __ex_table, "a"
758 .align 2
759 .long 00b, 03b
760 .long 01b, 03b
761 .long 02b, 03b
762 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 bdnz 00b
764 blr
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766_GLOBAL(_insl_ns)
767 cmpwi 0,r5,0
768 mtctr r5
769 subi r4,r4,4
770 blelr-
77100: lwz r5,0(r3)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020077201: eieio
77302: stwu r5,4(r4)
774 ISYNC_8xx
775 .section .fixup,"ax"
77603: blr
777 .text
778 .section __ex_table, "a"
779 .align 2
780 .long 00b, 03b
781 .long 01b, 03b
782 .long 02b, 03b
783 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 bdnz 00b
785 blr
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787_GLOBAL(_outsl_ns)
788 cmpwi 0,r5,0
789 mtctr r5
790 subi r4,r4,4
791 blelr-
79200: lwzu r5,4(r4)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020079301: stw r5,0(r3)
79402: eieio
795 ISYNC_8xx
796 .section .fixup,"ax"
79703: blr
798 .text
799 .section __ex_table, "a"
800 .align 2
801 .long 00b, 03b
802 .long 01b, 03b
803 .long 02b, 03b
804 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 bdnz 00b
806 blr
807
808/*
809 * Extended precision shifts.
810 *
811 * Updated to be valid for shift counts from 0 to 63 inclusive.
812 * -- Gabriel
813 *
814 * R3/R4 has 64 bit value
815 * R5 has shift count
816 * result in R3/R4
817 *
818 * ashrdi3: arithmetic right shift (sign propagation)
819 * lshrdi3: logical right shift
820 * ashldi3: left shift
821 */
822_GLOBAL(__ashrdi3)
823 subfic r6,r5,32
824 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
825 addi r7,r5,32 # could be xori, or addi with -32
826 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
827 rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0
828 sraw r7,r3,r7 # t2 = MSW >> (count-32)
829 or r4,r4,r6 # LSW |= t1
830 slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2
831 sraw r3,r3,r5 # MSW = MSW >> count
832 or r4,r4,r7 # LSW |= t2
833 blr
834
835_GLOBAL(__ashldi3)
836 subfic r6,r5,32
837 slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count
838 addi r7,r5,32 # could be xori, or addi with -32
839 srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count)
840 slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32)
841 or r3,r3,r6 # MSW |= t1
842 slw r4,r4,r5 # LSW = LSW << count
843 or r3,r3,r7 # MSW |= t2
844 blr
845
846_GLOBAL(__lshrdi3)
847 subfic r6,r5,32
848 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
849 addi r7,r5,32 # could be xori, or addi with -32
850 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
851 srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32)
852 or r4,r4,r6 # LSW |= t1
853 srw r3,r3,r5 # MSW = MSW >> count
854 or r4,r4,r7 # LSW |= t2
855 blr
856
857_GLOBAL(abs)
858 srawi r4,r3,31
859 xor r3,r3,r4
860 sub r3,r3,r4
861 blr
862
863_GLOBAL(_get_SP)
864 mr r3,r1 /* Close enough */
865 blr
866
867/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 * Create a kernel thread
869 * kernel_thread(fn, arg, flags)
870 */
871_GLOBAL(kernel_thread)
872 stwu r1,-16(r1)
873 stw r30,8(r1)
874 stw r31,12(r1)
875 mr r30,r3 /* function */
876 mr r31,r4 /* argument */
877 ori r3,r5,CLONE_VM /* flags */
878 oris r3,r3,CLONE_UNTRACED>>16
879 li r4,0 /* new sp (unused) */
880 li r0,__NR_clone
881 sc
882 cmpwi 0,r3,0 /* parent or child? */
883 bne 1f /* return if parent */
884 li r0,0 /* make top-level stack frame */
885 stwu r0,-16(r1)
886 mtlr r30 /* fn addr in lr */
887 mr r3,r31 /* load arg and call fn */
Matt Porterc9cf73a2005-07-31 22:34:52 -0700888 PPC440EP_ERR42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 blrl
890 li r0,__NR_exit /* exit if function returns */
891 li r3,0
892 sc
8931: lwz r30,8(r1)
894 lwz r31,12(r1)
895 addi r1,r1,16
896 blr
897
Arnd Bergmannfe742902006-10-02 02:18:34 -0700898_GLOBAL(kernel_execve)
899 li r0,__NR_execve
900 sc
901 bnslr
902 neg r3,r3
903 blr
904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905/*
906 * This routine is just here to keep GCC happy - sigh...
907 */
908_GLOBAL(__main)
909 blr
910