blob: 2b81e71d6b2db416c0efbd5126246f5f4e47246c [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
502 mtctr r4
5031: icbi 0,r6
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000504 addi r6,r6,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 bdnz 1b
506 sync
507 isync
508 blr
509
510/*
511 * Flush a particular page from the data cache to RAM, identified
512 * by its physical address. We turn off the MMU so we can just use
513 * the physical address (this may be a highmem page without a kernel
514 * mapping).
515 *
516 * void __flush_dcache_icache_phys(unsigned long physaddr)
517 */
518_GLOBAL(__flush_dcache_icache_phys)
519BEGIN_FTR_SECTION
520 blr /* for 601, do nothing */
David Gibson4508dc22007-06-13 14:52:57 +1000521END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 mfmsr r10
523 rlwinm r0,r10,0,28,26 /* clear DR */
524 mtmsr r0
525 isync
526 rlwinm r3,r3,0,0,19 /* Get page base address */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000527 li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 mtctr r4
529 mr r6,r3
5300: dcbst 0,r3 /* Write line to ram */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000531 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 bdnz 0b
533 sync
534 mtctr r4
5351: icbi 0,r6
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000536 addi r6,r6,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 bdnz 1b
538 sync
539 mtmsr r10 /* restore DR */
540 isync
541 blr
542
543/*
544 * Clear pages using the dcbz instruction, which doesn't cause any
545 * memory traffic (except to write out any cache lines which get
546 * displaced). This only works on cacheable memory.
547 *
548 * void clear_pages(void *page, int order) ;
549 */
550_GLOBAL(clear_pages)
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000551 li r0,4096/L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 slw r0,r0,r4
553 mtctr r0
554#ifdef CONFIG_8xx
555 li r4, 0
5561: stw r4, 0(r3)
557 stw r4, 4(r3)
558 stw r4, 8(r3)
559 stw r4, 12(r3)
560#else
5611: dcbz 0,r3
562#endif
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000563 addi r3,r3,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 bdnz 1b
565 blr
566
567/*
568 * Copy a whole page. We use the dcbz instruction on the destination
569 * to reduce memory traffic (it eliminates the unnecessary reads of
570 * the destination into cache). This requires that the destination
571 * is cacheable.
572 */
573#define COPY_16_BYTES \
574 lwz r6,4(r4); \
575 lwz r7,8(r4); \
576 lwz r8,12(r4); \
577 lwzu r9,16(r4); \
578 stw r6,4(r3); \
579 stw r7,8(r3); \
580 stw r8,12(r3); \
581 stwu r9,16(r3)
582
583_GLOBAL(copy_page)
584 addi r3,r3,-4
585 addi r4,r4,-4
586
587#ifdef CONFIG_8xx
588 /* don't use prefetch on 8xx */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000589 li r0,4096/L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 mtctr r0
5911: COPY_16_BYTES
592 bdnz 1b
593 blr
594
595#else /* not 8xx, we can prefetch */
596 li r5,4
597
598#if MAX_COPY_PREFETCH > 1
599 li r0,MAX_COPY_PREFETCH
600 li r11,4
601 mtctr r0
60211: dcbt r11,r4
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000603 addi r11,r11,L1_CACHE_BYTES
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 bdnz 11b
605#else /* MAX_COPY_PREFETCH == 1 */
606 dcbt r5,r4
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000607 li r11,L1_CACHE_BYTES+4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608#endif /* MAX_COPY_PREFETCH */
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000609 li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 crclr 4*cr0+eq
6112:
612 mtctr r0
6131:
614 dcbt r11,r4
615 dcbz r5,r3
616 COPY_16_BYTES
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000617#if L1_CACHE_BYTES >= 32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 COPY_16_BYTES
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000619#if L1_CACHE_BYTES >= 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 COPY_16_BYTES
621 COPY_16_BYTES
Stephen Rothwell7dffb722005-10-17 11:50:32 +1000622#if L1_CACHE_BYTES >= 128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 COPY_16_BYTES
624 COPY_16_BYTES
625 COPY_16_BYTES
626 COPY_16_BYTES
627#endif
628#endif
629#endif
630 bdnz 1b
631 beqlr
632 crnot 4*cr0+eq,4*cr0+eq
633 li r0,MAX_COPY_PREFETCH
634 li r11,4
635 b 2b
636#endif /* CONFIG_8xx */
637
638/*
639 * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
640 * void atomic_set_mask(atomic_t mask, atomic_t *addr);
641 */
642_GLOBAL(atomic_clear_mask)
64310: lwarx r5,0,r4
644 andc r5,r5,r3
645 PPC405_ERR77(0,r4)
646 stwcx. r5,0,r4
647 bne- 10b
648 blr
649_GLOBAL(atomic_set_mask)
65010: lwarx r5,0,r4
651 or r5,r5,r3
652 PPC405_ERR77(0,r4)
653 stwcx. r5,0,r4
654 bne- 10b
655 blr
656
657/*
658 * I/O string operations
659 *
660 * insb(port, buf, len)
661 * outsb(port, buf, len)
662 * insw(port, buf, len)
663 * outsw(port, buf, len)
664 * insl(port, buf, len)
665 * outsl(port, buf, len)
666 * insw_ns(port, buf, len)
667 * outsw_ns(port, buf, len)
668 * insl_ns(port, buf, len)
669 * outsl_ns(port, buf, len)
670 *
671 * The *_ns versions don't do byte-swapping.
672 */
673_GLOBAL(_insb)
674 cmpwi 0,r5,0
675 mtctr r5
676 subi r4,r4,1
677 blelr-
67800: lbz r5,0(r3)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020067901: eieio
68002: stbu r5,1(r4)
681 ISYNC_8xx
682 .section .fixup,"ax"
68303: blr
684 .text
685 .section __ex_table, "a"
686 .align 2
687 .long 00b, 03b
688 .long 01b, 03b
689 .long 02b, 03b
690 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 bdnz 00b
692 blr
693
694_GLOBAL(_outsb)
695 cmpwi 0,r5,0
696 mtctr r5
697 subi r4,r4,1
698 blelr-
69900: lbzu r5,1(r4)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020070001: stb r5,0(r3)
70102: eieio
702 ISYNC_8xx
703 .section .fixup,"ax"
70403: blr
705 .text
706 .section __ex_table, "a"
707 .align 2
708 .long 00b, 03b
709 .long 01b, 03b
710 .long 02b, 03b
711 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 bdnz 00b
713 blr
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715_GLOBAL(_insw_ns)
716 cmpwi 0,r5,0
717 mtctr r5
718 subi r4,r4,2
719 blelr-
72000: lhz r5,0(r3)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020072101: eieio
72202: sthu r5,2(r4)
723 ISYNC_8xx
724 .section .fixup,"ax"
72503: blr
726 .text
727 .section __ex_table, "a"
728 .align 2
729 .long 00b, 03b
730 .long 01b, 03b
731 .long 02b, 03b
732 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 bdnz 00b
734 blr
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736_GLOBAL(_outsw_ns)
737 cmpwi 0,r5,0
738 mtctr r5
739 subi r4,r4,2
740 blelr-
74100: lhzu r5,2(r4)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020074201: sth r5,0(r3)
74302: eieio
744 ISYNC_8xx
745 .section .fixup,"ax"
74603: blr
747 .text
748 .section __ex_table, "a"
749 .align 2
750 .long 00b, 03b
751 .long 01b, 03b
752 .long 02b, 03b
753 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 bdnz 00b
755 blr
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757_GLOBAL(_insl_ns)
758 cmpwi 0,r5,0
759 mtctr r5
760 subi r4,r4,4
761 blelr-
76200: lwz r5,0(r3)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020076301: eieio
76402: stwu r5,4(r4)
765 ISYNC_8xx
766 .section .fixup,"ax"
76703: blr
768 .text
769 .section __ex_table, "a"
770 .align 2
771 .long 00b, 03b
772 .long 01b, 03b
773 .long 02b, 03b
774 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 bdnz 00b
776 blr
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778_GLOBAL(_outsl_ns)
779 cmpwi 0,r5,0
780 mtctr r5
781 subi r4,r4,4
782 blelr-
78300: lwzu r5,4(r4)
Marcelo Tosatti55b63322005-11-05 14:06:24 -020078401: stw r5,0(r3)
78502: eieio
786 ISYNC_8xx
787 .section .fixup,"ax"
78803: blr
789 .text
790 .section __ex_table, "a"
791 .align 2
792 .long 00b, 03b
793 .long 01b, 03b
794 .long 02b, 03b
795 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 bdnz 00b
797 blr
798
799/*
800 * Extended precision shifts.
801 *
802 * Updated to be valid for shift counts from 0 to 63 inclusive.
803 * -- Gabriel
804 *
805 * R3/R4 has 64 bit value
806 * R5 has shift count
807 * result in R3/R4
808 *
809 * ashrdi3: arithmetic right shift (sign propagation)
810 * lshrdi3: logical right shift
811 * ashldi3: left shift
812 */
813_GLOBAL(__ashrdi3)
814 subfic r6,r5,32
815 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
816 addi r7,r5,32 # could be xori, or addi with -32
817 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
818 rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0
819 sraw r7,r3,r7 # t2 = MSW >> (count-32)
820 or r4,r4,r6 # LSW |= t1
821 slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2
822 sraw r3,r3,r5 # MSW = MSW >> count
823 or r4,r4,r7 # LSW |= t2
824 blr
825
826_GLOBAL(__ashldi3)
827 subfic r6,r5,32
828 slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count
829 addi r7,r5,32 # could be xori, or addi with -32
830 srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count)
831 slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32)
832 or r3,r3,r6 # MSW |= t1
833 slw r4,r4,r5 # LSW = LSW << count
834 or r3,r3,r7 # MSW |= t2
835 blr
836
837_GLOBAL(__lshrdi3)
838 subfic r6,r5,32
839 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
840 addi r7,r5,32 # could be xori, or addi with -32
841 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
842 srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32)
843 or r4,r4,r6 # LSW |= t1
844 srw r3,r3,r5 # MSW = MSW >> count
845 or r4,r4,r7 # LSW |= t2
846 blr
847
848_GLOBAL(abs)
849 srawi r4,r3,31
850 xor r3,r3,r4
851 sub r3,r3,r4
852 blr
853
854_GLOBAL(_get_SP)
855 mr r3,r1 /* Close enough */
856 blr
857
858/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 * Create a kernel thread
860 * kernel_thread(fn, arg, flags)
861 */
862_GLOBAL(kernel_thread)
863 stwu r1,-16(r1)
864 stw r30,8(r1)
865 stw r31,12(r1)
866 mr r30,r3 /* function */
867 mr r31,r4 /* argument */
868 ori r3,r5,CLONE_VM /* flags */
869 oris r3,r3,CLONE_UNTRACED>>16
870 li r4,0 /* new sp (unused) */
871 li r0,__NR_clone
872 sc
873 cmpwi 0,r3,0 /* parent or child? */
874 bne 1f /* return if parent */
875 li r0,0 /* make top-level stack frame */
876 stwu r0,-16(r1)
877 mtlr r30 /* fn addr in lr */
878 mr r3,r31 /* load arg and call fn */
Matt Porterc9cf73a2005-07-31 22:34:52 -0700879 PPC440EP_ERR42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 blrl
881 li r0,__NR_exit /* exit if function returns */
882 li r3,0
883 sc
8841: lwz r30,8(r1)
885 lwz r31,12(r1)
886 addi r1,r1,16
887 blr
888
Arnd Bergmannfe742902006-10-02 02:18:34 -0700889_GLOBAL(kernel_execve)
890 li r0,__NR_execve
891 sc
892 bnslr
893 neg r3,r3
894 blr
895
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896/*
897 * This routine is just here to keep GCC happy - sigh...
898 */
899_GLOBAL(__main)
900 blr
901