tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / arch / powerpc / mm / hash_low_64.S
1 /*
2  * ppc64 MMU hashtable management routines
3  *
4  * (c) Copyright IBM Corp. 2003, 2005
5  *
6  * Maintained by: Benjamin Herrenschmidt
7  *                <benh@kernel.crashing.org>
8  *
9  * This file is covered by the GNU Public Licence v2 as
10  * described in the kernel's COPYING file.
11  */
12
13 #include <asm/reg.h>
14 #include <asm/pgtable.h>
15 #include <asm/mmu.h>
16 #include <asm/page.h>
17 #include <asm/types.h>
18 #include <asm/ppc_asm.h>
19 #include <asm/asm-offsets.h>
20 #include <asm/cputable.h>
21
22         .text
23
24 /*
25  * Stackframe:
26  *              
27  *         +-> Back chain                       (SP + 256)
28  *         |   General register save area       (SP + 112)
29  *         |   Parameter save area              (SP + 48)
30  *         |   TOC save area                    (SP + 40)
31  *         |   link editor doubleword           (SP + 32)
32  *         |   compiler doubleword              (SP + 24)
33  *         |   LR save area                     (SP + 16)
34  *         |   CR save area                     (SP + 8)
35  * SP ---> +-- Back chain                       (SP + 0)
36  */
37
38 #ifndef CONFIG_PPC_64K_PAGES
39
40 /*****************************************************************************
41  *                                                                           *
42  *           4K SW & 4K HW pages implementation                              *
43  *                                                                           *
44  *****************************************************************************/
45
46
47 /*
48  * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
49  *               pte_t *ptep, unsigned long trap, int local, int ssize)
50  *
51  * Adds a 4K page to the hash table in a segment of 4K pages only
52  */
53
54 _GLOBAL(__hash_page_4K)
55         mflr    r0
56         std     r0,16(r1)
57         stdu    r1,-STACKFRAMESIZE(r1)
58         /* Save all params that we need after a function call */
59         std     r6,STK_PARAM(R6)(r1)
60         std     r8,STK_PARAM(R8)(r1)
61         std     r9,STK_PARAM(R9)(r1)
62         
63         /* Save non-volatile registers.
64          * r31 will hold "old PTE"
65          * r30 is "new PTE"
66          * r29 is vpn
67          * r28 is a hash value
68          * r27 is hashtab mask (maybe dynamic patched instead ?)
69          */
70         std     r27,STK_REG(R27)(r1)
71         std     r28,STK_REG(R28)(r1)
72         std     r29,STK_REG(R29)(r1)
73         std     r30,STK_REG(R30)(r1)
74         std     r31,STK_REG(R31)(r1)
75         
76         /* Step 1:
77          *
78          * Check permissions, atomically mark the linux PTE busy
79          * and hashed.
80          */ 
81 1:
82         ldarx   r31,0,r6
83         /* Check access rights (access & ~(pte_val(*ptep))) */
84         andc.   r0,r4,r31
85         bne-    htab_wrong_access
86         /* Check if PTE is busy */
87         andi.   r0,r31,_PAGE_BUSY
88         /* If so, just bail out and refault if needed. Someone else
89          * is changing this PTE anyway and might hash it.
90          */
91         bne-    htab_bail_ok
92
93         /* Prepare new PTE value (turn access RW into DIRTY, then
94          * add BUSY,HASHPTE and ACCESSED)
95          */
96         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
97         or      r30,r30,r31
98         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
99         /* Write the linux PTE atomically (setting busy) */
100         stdcx.  r30,0,r6
101         bne-    1b
102         isync
103
104         /* Step 2:
105          *
106          * Insert/Update the HPTE in the hash table. At this point,
107          * r4 (access) is re-useable, we use it for the new HPTE flags
108          */
109
110 BEGIN_FTR_SECTION
111         cmpdi   r9,0                    /* check segment size */
112         bne     3f
113 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
114         /* Calc vpn and put it in r29 */
115         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
116         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
117         or      r29,r28,r29
118         /*
119          * Calculate hash value for primary slot and store it in r28
120          * r3 = va, r5 = vsid
121          * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
122          */
123         rldicl  r0,r3,64-12,48
124         xor     r28,r5,r0               /* hash */
125         b       4f
126
127 3:      /* Calc vpn and put it in r29 */
128         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
129         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
130         or      r29,r28,r29
131
132         /*
133          * calculate hash value for primary slot and
134          * store it in r28 for 1T segment
135          * r3 = va, r5 = vsid
136          */
137         sldi    r28,r5,25               /* vsid << 25 */
138         /* r0 =  (va >> 12) & ((1ul << (40 - 12)) -1) */
139         rldicl  r0,r3,64-12,36
140         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
141         xor     r28,r28,r0              /* hash */
142
143         /* Convert linux PTE bits into HW equivalents */
144 4:      andi.   r3,r30,0x1fe            /* Get basic set of flags */
145         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
146         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
147         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
148         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
149         andc    r0,r30,r0               /* r0 = pte & ~r0 */
150         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
151         ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
152
153         /* We eventually do the icache sync here (maybe inline that
154          * code rather than call a C function...) 
155          */
156 BEGIN_FTR_SECTION
157         mr      r4,r30
158         mr      r5,r7
159         bl      .hash_page_do_lazy_icache
160 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
161
162         /* At this point, r3 contains new PP bits, save them in
163          * place of "access" in the param area (sic)
164          */
165         std     r3,STK_PARAM(R4)(r1)
166
167         /* Get htab_hash_mask */
168         ld      r4,htab_hash_mask@got(2)
169         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
170
171         /* Check if we may already be in the hashtable, in this case, we
172          * go to out-of-line code to try to modify the HPTE
173          */
174         andi.   r0,r31,_PAGE_HASHPTE
175         bne     htab_modify_pte
176
177 htab_insert_pte:
178         /* Clear hpte bits in new pte (we also clear BUSY btw) and
179          * add _PAGE_HASHPTE
180          */
181         lis     r0,_PAGE_HPTEFLAGS@h
182         ori     r0,r0,_PAGE_HPTEFLAGS@l
183         andc    r30,r30,r0
184         ori     r30,r30,_PAGE_HASHPTE
185
186         /* physical address r5 */
187         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
188         sldi    r5,r5,PAGE_SHIFT
189
190         /* Calculate primary group hash */
191         and     r0,r28,r27
192         rldicr  r3,r0,3,63-3            /* r3 = (hash & mask) << 3 */
193
194         /* Call ppc_md.hpte_insert */
195         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
196         mr      r4,r29                  /* Retrieve vpn */
197         li      r7,0                    /* !bolted, !secondary */
198         li      r8,MMU_PAGE_4K          /* page size */
199         li      r9,MMU_PAGE_4K          /* actual page size */
200         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
201 _GLOBAL(htab_call_hpte_insert1)
202         bl      .                       /* Patched by htab_finish_init() */
203         cmpdi   0,r3,0
204         bge     htab_pte_insert_ok      /* Insertion successful */
205         cmpdi   0,r3,-2                 /* Critical failure */
206         beq-    htab_pte_insert_failure
207
208         /* Now try secondary slot */
209         
210         /* physical address r5 */
211         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
212         sldi    r5,r5,PAGE_SHIFT
213
214         /* Calculate secondary group hash */
215         andc    r0,r27,r28
216         rldicr  r3,r0,3,63-3    /* r0 = (~hash & mask) << 3 */
217         
218         /* Call ppc_md.hpte_insert */
219         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
220         mr      r4,r29                  /* Retrieve vpn */
221         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
222         li      r8,MMU_PAGE_4K          /* page size */
223         li      r9,MMU_PAGE_4K          /* actual page size */
224         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
225 _GLOBAL(htab_call_hpte_insert2)
226         bl      .                       /* Patched by htab_finish_init() */
227         cmpdi   0,r3,0
228         bge+    htab_pte_insert_ok      /* Insertion successful */
229         cmpdi   0,r3,-2                 /* Critical failure */
230         beq-    htab_pte_insert_failure
231
232         /* Both are full, we need to evict something */
233         mftb    r0
234         /* Pick a random group based on TB */
235         andi.   r0,r0,1
236         mr      r5,r28
237         bne     2f
238         not     r5,r5
239 2:      and     r0,r5,r27
240         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */   
241         /* Call ppc_md.hpte_remove */
242 _GLOBAL(htab_call_hpte_remove)
243         bl      .                       /* Patched by htab_finish_init() */
244
245         /* Try all again */
246         b       htab_insert_pte 
247
248 htab_bail_ok:
249         li      r3,0
250         b       htab_bail
251
252 htab_pte_insert_ok:
253         /* Insert slot number & secondary bit in PTE */
254         rldimi  r30,r3,12,63-15
255                 
256         /* Write out the PTE with a normal write
257          * (maybe add eieio may be good still ?)
258          */
259 htab_write_out_pte:
260         ld      r6,STK_PARAM(R6)(r1)
261         std     r30,0(r6)
262         li      r3, 0
263 htab_bail:
264         ld      r27,STK_REG(R27)(r1)
265         ld      r28,STK_REG(R28)(r1)
266         ld      r29,STK_REG(R29)(r1)
267         ld      r30,STK_REG(R30)(r1)
268         ld      r31,STK_REG(R31)(r1)
269         addi    r1,r1,STACKFRAMESIZE
270         ld      r0,16(r1)
271         mtlr    r0
272         blr
273
274 htab_modify_pte:
275         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
276         mr      r4,r3
277         rlwinm  r3,r31,32-12,29,31
278
279         /* Secondary group ? if yes, get a inverted hash value */
280         mr      r5,r28
281         andi.   r0,r31,_PAGE_SECONDARY
282         beq     1f
283         not     r5,r5
284 1:
285         /* Calculate proper slot value for ppc_md.hpte_updatepp */
286         and     r0,r5,r27
287         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
288         add     r3,r0,r3        /* add slot idx */
289
290         /* Call ppc_md.hpte_updatepp */
291         mr      r5,r29                  /* vpn */
292         li      r6,MMU_PAGE_4K          /* page size */
293         ld      r7,STK_PARAM(R9)(r1)    /* segment size */
294         ld      r8,STK_PARAM(R8)(r1)    /* get "local" param */
295 _GLOBAL(htab_call_hpte_updatepp)
296         bl      .                       /* Patched by htab_finish_init() */
297
298         /* if we failed because typically the HPTE wasn't really here
299          * we try an insertion. 
300          */
301         cmpdi   0,r3,-1
302         beq-    htab_insert_pte
303
304         /* Clear the BUSY bit and Write out the PTE */
305         li      r0,_PAGE_BUSY
306         andc    r30,r30,r0
307         b       htab_write_out_pte
308
309 htab_wrong_access:
310         /* Bail out clearing reservation */
311         stdcx.  r31,0,r6
312         li      r3,1
313         b       htab_bail
314
315 htab_pte_insert_failure:
316         /* Bail out restoring old PTE */
317         ld      r6,STK_PARAM(R6)(r1)
318         std     r31,0(r6)
319         li      r3,-1
320         b       htab_bail
321
322
323 #else /* CONFIG_PPC_64K_PAGES */
324
325
326 /*****************************************************************************
327  *                                                                           *
328  *           64K SW & 4K or 64K HW in a 4K segment pages implementation      *
329  *                                                                           *
330  *****************************************************************************/
331
332 /* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
333  *               pte_t *ptep, unsigned long trap, int local, int ssize,
334  *               int subpg_prot)
335  */
336
337 /*
338  * For now, we do NOT implement Admixed pages
339  */
340 _GLOBAL(__hash_page_4K)
341         mflr    r0
342         std     r0,16(r1)
343         stdu    r1,-STACKFRAMESIZE(r1)
344         /* Save all params that we need after a function call */
345         std     r6,STK_PARAM(R6)(r1)
346         std     r8,STK_PARAM(R8)(r1)
347         std     r9,STK_PARAM(R9)(r1)
348
349         /* Save non-volatile registers.
350          * r31 will hold "old PTE"
351          * r30 is "new PTE"
352          * r29 is vpn
353          * r28 is a hash value
354          * r27 is hashtab mask (maybe dynamic patched instead ?)
355          * r26 is the hidx mask
356          * r25 is the index in combo page
357          */
358         std     r25,STK_REG(R25)(r1)
359         std     r26,STK_REG(R26)(r1)
360         std     r27,STK_REG(R27)(r1)
361         std     r28,STK_REG(R28)(r1)
362         std     r29,STK_REG(R29)(r1)
363         std     r30,STK_REG(R30)(r1)
364         std     r31,STK_REG(R31)(r1)
365
366         /* Step 1:
367          *
368          * Check permissions, atomically mark the linux PTE busy
369          * and hashed.
370          */
371 1:
372         ldarx   r31,0,r6
373         /* Check access rights (access & ~(pte_val(*ptep))) */
374         andc.   r0,r4,r31
375         bne-    htab_wrong_access
376         /* Check if PTE is busy */
377         andi.   r0,r31,_PAGE_BUSY
378         /* If so, just bail out and refault if needed. Someone else
379          * is changing this PTE anyway and might hash it.
380          */
381         bne-    htab_bail_ok
382         /* Prepare new PTE value (turn access RW into DIRTY, then
383          * add BUSY and ACCESSED)
384          */
385         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
386         or      r30,r30,r31
387         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
388         oris    r30,r30,_PAGE_COMBO@h
389         /* Write the linux PTE atomically (setting busy) */
390         stdcx.  r30,0,r6
391         bne-    1b
392         isync
393
394         /* Step 2:
395          *
396          * Insert/Update the HPTE in the hash table. At this point,
397          * r4 (access) is re-useable, we use it for the new HPTE flags
398          */
399
400         /* Load the hidx index */
401         rldicl  r25,r3,64-12,60
402
403 BEGIN_FTR_SECTION
404         cmpdi   r9,0                    /* check segment size */
405         bne     3f
406 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
407         /* Calc vpn and put it in r29 */
408         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
409         /*
410          * clrldi r3,r3,64 - SID_SHIFT -->  ea & 0xfffffff
411          * srdi  r28,r3,VPN_SHIFT
412          */
413         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
414         or      r29,r28,r29
415         /*
416          * Calculate hash value for primary slot and store it in r28
417          * r3 = va, r5 = vsid
418          * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
419          */
420         rldicl  r0,r3,64-12,48
421         xor     r28,r5,r0               /* hash */
422         b       4f
423
424 3:      /* Calc vpn and put it in r29 */
425         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
426         /*
427          * clrldi r3,r3,64 - SID_SHIFT_1T -->  ea & 0xffffffffff
428          * srdi r28,r3,VPN_SHIFT
429          */
430         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
431         or      r29,r28,r29
432
433         /*
434          * Calculate hash value for primary slot and
435          * store it in r28  for 1T segment
436          * r3 = va, r5 = vsid
437          */
438         sldi    r28,r5,25               /* vsid << 25 */
439         /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */
440         rldicl  r0,r3,64-12,36
441         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
442         xor     r28,r28,r0              /* hash */
443
444         /* Convert linux PTE bits into HW equivalents */
445 4:
446 #ifdef CONFIG_PPC_SUBPAGE_PROT
447         andc    r10,r30,r10
448         andi.   r3,r10,0x1fe            /* Get basic set of flags */
449         rlwinm  r0,r10,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
450 #else
451         andi.   r3,r30,0x1fe            /* Get basic set of flags */
452         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
453 #endif
454         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
455         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
456         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
457         andc    r0,r3,r0                /* r0 = pte & ~r0 */
458         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
459         ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
460
461         /* We eventually do the icache sync here (maybe inline that
462          * code rather than call a C function...)
463          */
464 BEGIN_FTR_SECTION
465         mr      r4,r30
466         mr      r5,r7
467         bl      .hash_page_do_lazy_icache
468 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
469
470         /* At this point, r3 contains new PP bits, save them in
471          * place of "access" in the param area (sic)
472          */
473         std     r3,STK_PARAM(R4)(r1)
474
475         /* Get htab_hash_mask */
476         ld      r4,htab_hash_mask@got(2)
477         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
478
479         /* Check if we may already be in the hashtable, in this case, we
480          * go to out-of-line code to try to modify the HPTE. We look for
481          * the bit at (1 >> (index + 32))
482          */
483         rldicl. r0,r31,64-12,48
484         li      r26,0                   /* Default hidx */
485         beq     htab_insert_pte
486
487         /*
488          * Check if the pte was already inserted into the hash table
489          * as a 64k HW page, and invalidate the 64k HPTE if so.
490          */
491         andis.  r0,r31,_PAGE_COMBO@h
492         beq     htab_inval_old_hpte
493
494         ld      r6,STK_PARAM(R6)(r1)
495         ori     r26,r6,PTE_PAGE_HIDX_OFFSET /* Load the hidx mask. */
496         ld      r26,0(r26)
497         addi    r5,r25,36               /* Check actual HPTE_SUB bit, this */
498         rldcr.  r0,r31,r5,0             /* must match pgtable.h definition */
499         bne     htab_modify_pte
500
501 htab_insert_pte:
502         /* real page number in r5, PTE RPN value + index */
503         andis.  r0,r31,_PAGE_4K_PFN@h
504         srdi    r5,r31,PTE_RPN_SHIFT
505         bne-    htab_special_pfn
506         sldi    r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
507         add     r5,r5,r25
508 htab_special_pfn:
509         sldi    r5,r5,HW_PAGE_SHIFT
510
511         /* Calculate primary group hash */
512         and     r0,r28,r27
513         rldicr  r3,r0,3,63-3            /* r0 = (hash & mask) << 3 */
514
515         /* Call ppc_md.hpte_insert */
516         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
517         mr      r4,r29                  /* Retrieve vpn */
518         li      r7,0                    /* !bolted, !secondary */
519         li      r8,MMU_PAGE_4K          /* page size */
520         li      r9,MMU_PAGE_4K          /* actual page size */
521         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
522 _GLOBAL(htab_call_hpte_insert1)
523         bl      .                       /* patched by htab_finish_init() */
524         cmpdi   0,r3,0
525         bge     htab_pte_insert_ok      /* Insertion successful */
526         cmpdi   0,r3,-2                 /* Critical failure */
527         beq-    htab_pte_insert_failure
528
529         /* Now try secondary slot */
530
531         /* real page number in r5, PTE RPN value + index */
532         andis.  r0,r31,_PAGE_4K_PFN@h
533         srdi    r5,r31,PTE_RPN_SHIFT
534         bne-    3f
535         sldi    r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
536         add     r5,r5,r25
537 3:      sldi    r5,r5,HW_PAGE_SHIFT
538
539         /* Calculate secondary group hash */
540         andc    r0,r27,r28
541         rldicr  r3,r0,3,63-3            /* r0 = (~hash & mask) << 3 */
542
543         /* Call ppc_md.hpte_insert */
544         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
545         mr      r4,r29                  /* Retrieve vpn */
546         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
547         li      r8,MMU_PAGE_4K          /* page size */
548         li      r9,MMU_PAGE_4K          /* actual page size */
549         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
550 _GLOBAL(htab_call_hpte_insert2)
551         bl      .                       /* patched by htab_finish_init() */
552         cmpdi   0,r3,0
553         bge+    htab_pte_insert_ok      /* Insertion successful */
554         cmpdi   0,r3,-2                 /* Critical failure */
555         beq-    htab_pte_insert_failure
556
557         /* Both are full, we need to evict something */
558         mftb    r0
559         /* Pick a random group based on TB */
560         andi.   r0,r0,1
561         mr      r5,r28
562         bne     2f
563         not     r5,r5
564 2:      and     r0,r5,r27
565         rldicr  r3,r0,3,63-3            /* r0 = (hash & mask) << 3 */
566         /* Call ppc_md.hpte_remove */
567 _GLOBAL(htab_call_hpte_remove)
568         bl      .                       /* patched by htab_finish_init() */
569
570         /* Try all again */
571         b       htab_insert_pte
572
573         /*
574          * Call out to C code to invalidate an 64k HW HPTE that is
575          * useless now that the segment has been switched to 4k pages.
576          */
577 htab_inval_old_hpte:
578         mr      r3,r29                  /* vpn */
579         mr      r4,r31                  /* PTE.pte */
580         li      r5,0                    /* PTE.hidx */
581         li      r6,MMU_PAGE_64K         /* psize */
582         ld      r7,STK_PARAM(R9)(r1)    /* ssize */
583         ld      r8,STK_PARAM(R8)(r1)    /* local */
584         bl      .flush_hash_page
585         /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */
586         lis     r0,_PAGE_HPTE_SUB@h
587         ori     r0,r0,_PAGE_HPTE_SUB@l
588         andc    r30,r30,r0
589         b       htab_insert_pte
590         
591 htab_bail_ok:
592         li      r3,0
593         b       htab_bail
594
595 htab_pte_insert_ok:
596         /* Insert slot number & secondary bit in PTE second half,
597          * clear _PAGE_BUSY and set approriate HPTE slot bit
598          */
599         ld      r6,STK_PARAM(R6)(r1)
600         li      r0,_PAGE_BUSY
601         andc    r30,r30,r0
602         /* HPTE SUB bit */
603         li      r0,1
604         subfic  r5,r25,27               /* Must match bit position in */
605         sld     r0,r0,r5                /* pgtable.h */
606         or      r30,r30,r0
607         /* hindx */
608         sldi    r5,r25,2
609         sld     r3,r3,r5
610         li      r4,0xf
611         sld     r4,r4,r5
612         andc    r26,r26,r4
613         or      r26,r26,r3
614         ori     r5,r6,PTE_PAGE_HIDX_OFFSET
615         std     r26,0(r5)
616         lwsync
617         std     r30,0(r6)
618         li      r3, 0
619 htab_bail:
620         ld      r25,STK_REG(R25)(r1)
621         ld      r26,STK_REG(R26)(r1)
622         ld      r27,STK_REG(R27)(r1)
623         ld      r28,STK_REG(R28)(r1)
624         ld      r29,STK_REG(R29)(r1)
625         ld      r30,STK_REG(R30)(r1)
626         ld      r31,STK_REG(R31)(r1)
627         addi    r1,r1,STACKFRAMESIZE
628         ld      r0,16(r1)
629         mtlr    r0
630         blr
631
632 htab_modify_pte:
633         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
634         mr      r4,r3
635         sldi    r5,r25,2
636         srd     r3,r26,r5
637
638         /* Secondary group ? if yes, get a inverted hash value */
639         mr      r5,r28
640         andi.   r0,r3,0x8 /* page secondary ? */
641         beq     1f
642         not     r5,r5
643 1:      andi.   r3,r3,0x7 /* extract idx alone */
644
645         /* Calculate proper slot value for ppc_md.hpte_updatepp */
646         and     r0,r5,r27
647         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
648         add     r3,r0,r3        /* add slot idx */
649
650         /* Call ppc_md.hpte_updatepp */
651         mr      r5,r29                  /* vpn */
652         li      r6,MMU_PAGE_4K          /* page size */
653         ld      r7,STK_PARAM(R9)(r1)    /* segment size */
654         ld      r8,STK_PARAM(R8)(r1)    /* get "local" param */
655 _GLOBAL(htab_call_hpte_updatepp)
656         bl      .                       /* patched by htab_finish_init() */
657
658         /* if we failed because typically the HPTE wasn't really here
659          * we try an insertion.
660          */
661         cmpdi   0,r3,-1
662         beq-    htab_insert_pte
663
664         /* Clear the BUSY bit and Write out the PTE */
665         li      r0,_PAGE_BUSY
666         andc    r30,r30,r0
667         ld      r6,STK_PARAM(R6)(r1)
668         std     r30,0(r6)
669         li      r3,0
670         b       htab_bail
671
672 htab_wrong_access:
673         /* Bail out clearing reservation */
674         stdcx.  r31,0,r6
675         li      r3,1
676         b       htab_bail
677
678 htab_pte_insert_failure:
679         /* Bail out restoring old PTE */
680         ld      r6,STK_PARAM(R6)(r1)
681         std     r31,0(r6)
682         li      r3,-1
683         b       htab_bail
684
685 #endif /* CONFIG_PPC_64K_PAGES */
686
687 #ifdef CONFIG_PPC_HAS_HASH_64K
688
689 /*****************************************************************************
690  *                                                                           *
691  *           64K SW & 64K HW in a 64K segment pages implementation           *
692  *                                                                           *
693  *****************************************************************************/
694
695 _GLOBAL(__hash_page_64K)
696         mflr    r0
697         std     r0,16(r1)
698         stdu    r1,-STACKFRAMESIZE(r1)
699         /* Save all params that we need after a function call */
700         std     r6,STK_PARAM(R6)(r1)
701         std     r8,STK_PARAM(R8)(r1)
702         std     r9,STK_PARAM(R9)(r1)
703
704         /* Save non-volatile registers.
705          * r31 will hold "old PTE"
706          * r30 is "new PTE"
707          * r29 is vpn
708          * r28 is a hash value
709          * r27 is hashtab mask (maybe dynamic patched instead ?)
710          */
711         std     r27,STK_REG(R27)(r1)
712         std     r28,STK_REG(R28)(r1)
713         std     r29,STK_REG(R29)(r1)
714         std     r30,STK_REG(R30)(r1)
715         std     r31,STK_REG(R31)(r1)
716
717         /* Step 1:
718          *
719          * Check permissions, atomically mark the linux PTE busy
720          * and hashed.
721          */
722 1:
723         ldarx   r31,0,r6
724         /* Check access rights (access & ~(pte_val(*ptep))) */
725         andc.   r0,r4,r31
726         bne-    ht64_wrong_access
727         /* Check if PTE is busy */
728         andi.   r0,r31,_PAGE_BUSY
729         /* If so, just bail out and refault if needed. Someone else
730          * is changing this PTE anyway and might hash it.
731          */
732         bne-    ht64_bail_ok
733 BEGIN_FTR_SECTION
734         /* Check if PTE has the cache-inhibit bit set */
735         andi.   r0,r31,_PAGE_NO_CACHE
736         /* If so, bail out and refault as a 4k page */
737         bne-    ht64_bail_ok
738 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)
739         /* Prepare new PTE value (turn access RW into DIRTY, then
740          * add BUSY and ACCESSED)
741          */
742         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
743         or      r30,r30,r31
744         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
745         /* Write the linux PTE atomically (setting busy) */
746         stdcx.  r30,0,r6
747         bne-    1b
748         isync
749
750         /* Step 2:
751          *
752          * Insert/Update the HPTE in the hash table. At this point,
753          * r4 (access) is re-useable, we use it for the new HPTE flags
754          */
755
756 BEGIN_FTR_SECTION
757         cmpdi   r9,0                    /* check segment size */
758         bne     3f
759 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
760         /* Calc vpn and put it in r29 */
761         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
762         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
763         or      r29,r28,r29
764
765         /* Calculate hash value for primary slot and store it in r28
766          * r3 = va, r5 = vsid
767          * r0 = (va >> 16) & ((1ul << (28 - 16)) -1)
768          */
769         rldicl  r0,r3,64-16,52
770         xor     r28,r5,r0               /* hash */
771         b       4f
772
773 3:      /* Calc vpn and put it in r29 */
774         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
775         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
776         or      r29,r28,r29
777         /*
778          * calculate hash value for primary slot and
779          * store it in r28 for 1T segment
780          * r3 = va, r5 = vsid
781          */
782         sldi    r28,r5,25               /* vsid << 25 */
783         /* r0 = (va >> 16) & ((1ul << (40 - 16)) -1) */
784         rldicl  r0,r3,64-16,40
785         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
786         xor     r28,r28,r0              /* hash */
787
788         /* Convert linux PTE bits into HW equivalents */
789 4:      andi.   r3,r30,0x1fe            /* Get basic set of flags */
790         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
791         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
792         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
793         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
794         andc    r0,r30,r0               /* r0 = pte & ~r0 */
795         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
796         ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
797
798         /* We eventually do the icache sync here (maybe inline that
799          * code rather than call a C function...)
800          */
801 BEGIN_FTR_SECTION
802         mr      r4,r30
803         mr      r5,r7
804         bl      .hash_page_do_lazy_icache
805 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
806
807         /* At this point, r3 contains new PP bits, save them in
808          * place of "access" in the param area (sic)
809          */
810         std     r3,STK_PARAM(R4)(r1)
811
812         /* Get htab_hash_mask */
813         ld      r4,htab_hash_mask@got(2)
814         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
815
816         /* Check if we may already be in the hashtable, in this case, we
817          * go to out-of-line code to try to modify the HPTE
818          */
819         rldicl. r0,r31,64-12,48
820         bne     ht64_modify_pte
821
822 ht64_insert_pte:
823         /* Clear hpte bits in new pte (we also clear BUSY btw) and
824          * add _PAGE_HPTE_SUB0
825          */
826         lis     r0,_PAGE_HPTEFLAGS@h
827         ori     r0,r0,_PAGE_HPTEFLAGS@l
828         andc    r30,r30,r0
829 #ifdef CONFIG_PPC_64K_PAGES
830         oris    r30,r30,_PAGE_HPTE_SUB0@h
831 #else
832         ori     r30,r30,_PAGE_HASHPTE
833 #endif
834         /* Phyical address in r5 */
835         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
836         sldi    r5,r5,PAGE_SHIFT
837
838         /* Calculate primary group hash */
839         and     r0,r28,r27
840         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */
841
842         /* Call ppc_md.hpte_insert */
843         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
844         mr      r4,r29                  /* Retrieve vpn */
845         li      r7,0                    /* !bolted, !secondary */
846         li      r8,MMU_PAGE_64K
847         li      r9,MMU_PAGE_64K         /* actual page size */
848         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
849 _GLOBAL(ht64_call_hpte_insert1)
850         bl      .                       /* patched by htab_finish_init() */
851         cmpdi   0,r3,0
852         bge     ht64_pte_insert_ok      /* Insertion successful */
853         cmpdi   0,r3,-2                 /* Critical failure */
854         beq-    ht64_pte_insert_failure
855
856         /* Now try secondary slot */
857
858         /* Phyical address in r5 */
859         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
860         sldi    r5,r5,PAGE_SHIFT
861
862         /* Calculate secondary group hash */
863         andc    r0,r27,r28
864         rldicr  r3,r0,3,63-3    /* r0 = (~hash & mask) << 3 */
865
866         /* Call ppc_md.hpte_insert */
867         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
868         mr      r4,r29                  /* Retrieve vpn */
869         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
870         li      r8,MMU_PAGE_64K
871         li      r9,MMU_PAGE_64K         /* actual page size */
872         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
873 _GLOBAL(ht64_call_hpte_insert2)
874         bl      .                       /* patched by htab_finish_init() */
875         cmpdi   0,r3,0
876         bge+    ht64_pte_insert_ok      /* Insertion successful */
877         cmpdi   0,r3,-2                 /* Critical failure */
878         beq-    ht64_pte_insert_failure
879
880         /* Both are full, we need to evict something */
881         mftb    r0
882         /* Pick a random group based on TB */
883         andi.   r0,r0,1
884         mr      r5,r28
885         bne     2f
886         not     r5,r5
887 2:      and     r0,r5,r27
888         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */
889         /* Call ppc_md.hpte_remove */
890 _GLOBAL(ht64_call_hpte_remove)
891         bl      .                       /* patched by htab_finish_init() */
892
893         /* Try all again */
894         b       ht64_insert_pte
895
896 ht64_bail_ok:
897         li      r3,0
898         b       ht64_bail
899
900 ht64_pte_insert_ok:
901         /* Insert slot number & secondary bit in PTE */
902         rldimi  r30,r3,12,63-15
903
904         /* Write out the PTE with a normal write
905          * (maybe add eieio may be good still ?)
906          */
907 ht64_write_out_pte:
908         ld      r6,STK_PARAM(R6)(r1)
909         std     r30,0(r6)
910         li      r3, 0
911 ht64_bail:
912         ld      r27,STK_REG(R27)(r1)
913         ld      r28,STK_REG(R28)(r1)
914         ld      r29,STK_REG(R29)(r1)
915         ld      r30,STK_REG(R30)(r1)
916         ld      r31,STK_REG(R31)(r1)
917         addi    r1,r1,STACKFRAMESIZE
918         ld      r0,16(r1)
919         mtlr    r0
920         blr
921
922 ht64_modify_pte:
923         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
924         mr      r4,r3
925         rlwinm  r3,r31,32-12,29,31
926
927         /* Secondary group ? if yes, get a inverted hash value */
928         mr      r5,r28
929         andi.   r0,r31,_PAGE_F_SECOND
930         beq     1f
931         not     r5,r5
932 1:
933         /* Calculate proper slot value for ppc_md.hpte_updatepp */
934         and     r0,r5,r27
935         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
936         add     r3,r0,r3        /* add slot idx */
937
938         /* Call ppc_md.hpte_updatepp */
939         mr      r5,r29                  /* vpn */
940         li      r6,MMU_PAGE_64K
941         ld      r7,STK_PARAM(R9)(r1)    /* segment size */
942         ld      r8,STK_PARAM(R8)(r1)    /* get "local" param */
943 _GLOBAL(ht64_call_hpte_updatepp)
944         bl      .                       /* patched by htab_finish_init() */
945
946         /* if we failed because typically the HPTE wasn't really here
947          * we try an insertion.
948          */
949         cmpdi   0,r3,-1
950         beq-    ht64_insert_pte
951
952         /* Clear the BUSY bit and Write out the PTE */
953         li      r0,_PAGE_BUSY
954         andc    r30,r30,r0
955         b       ht64_write_out_pte
956
957 ht64_wrong_access:
958         /* Bail out clearing reservation */
959         stdcx.  r31,0,r6
960         li      r3,1
961         b       ht64_bail
962
963 ht64_pte_insert_failure:
964         /* Bail out restoring old PTE */
965         ld      r6,STK_PARAM(R6)(r1)
966         std     r31,0(r6)
967         li      r3,-1
968         b       ht64_bail
969
970
971 #endif /* CONFIG_PPC_HAS_HASH_64K */
972
973
974 /*****************************************************************************
975  *                                                                           *
976  *           Huge pages implementation is in hugetlbpage.c                   *
977  *                                                                           *
978  *****************************************************************************/