Linux 3.17-rc2
[linux/fpc-iii.git] / arch / powerpc / mm / hash_low_64.S
blob057cbbb4c576d3377ca6f21b46d4b574114ef2be
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  */
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>
22         .text
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  */
38 #ifndef CONFIG_PPC_64K_PAGES
40 /*****************************************************************************
41  *                                                                           *
42  *           4K SW & 4K HW pages implementation                              *
43  *                                                                           *
44  *****************************************************************************/
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  */
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          */ 
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
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
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          */
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
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
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 */
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         /*
152          * Always add "C" bit for perf. Memory coherence is always enabled
153          */
154         ori     r3,r3,HPTE_R_C | HPTE_R_M
156         /* We eventually do the icache sync here (maybe inline that
157          * code rather than call a C function...) 
158          */
159 BEGIN_FTR_SECTION
160         mr      r4,r30
161         mr      r5,r7
162         bl      hash_page_do_lazy_icache
163 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
165         /* At this point, r3 contains new PP bits, save them in
166          * place of "access" in the param area (sic)
167          */
168         std     r3,STK_PARAM(R4)(r1)
170         /* Get htab_hash_mask */
171         ld      r4,htab_hash_mask@got(2)
172         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
174         /* Check if we may already be in the hashtable, in this case, we
175          * go to out-of-line code to try to modify the HPTE
176          */
177         andi.   r0,r31,_PAGE_HASHPTE
178         bne     htab_modify_pte
180 htab_insert_pte:
181         /* Clear hpte bits in new pte (we also clear BUSY btw) and
182          * add _PAGE_HASHPTE
183          */
184         lis     r0,_PAGE_HPTEFLAGS@h
185         ori     r0,r0,_PAGE_HPTEFLAGS@l
186         andc    r30,r30,r0
187         ori     r30,r30,_PAGE_HASHPTE
189         /* physical address r5 */
190         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
191         sldi    r5,r5,PAGE_SHIFT
193         /* Calculate primary group hash */
194         and     r0,r28,r27
195         rldicr  r3,r0,3,63-3            /* r3 = (hash & mask) << 3 */
197         /* Call ppc_md.hpte_insert */
198         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
199         mr      r4,r29                  /* Retrieve vpn */
200         li      r7,0                    /* !bolted, !secondary */
201         li      r8,MMU_PAGE_4K          /* page size */
202         li      r9,MMU_PAGE_4K          /* actual page size */
203         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
204 .globl htab_call_hpte_insert1
205 htab_call_hpte_insert1:
206         bl      .                       /* Patched by htab_finish_init() */
207         cmpdi   0,r3,0
208         bge     htab_pte_insert_ok      /* Insertion successful */
209         cmpdi   0,r3,-2                 /* Critical failure */
210         beq-    htab_pte_insert_failure
212         /* Now try secondary slot */
213         
214         /* physical address r5 */
215         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
216         sldi    r5,r5,PAGE_SHIFT
218         /* Calculate secondary group hash */
219         andc    r0,r27,r28
220         rldicr  r3,r0,3,63-3    /* r0 = (~hash & mask) << 3 */
221         
222         /* Call ppc_md.hpte_insert */
223         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
224         mr      r4,r29                  /* Retrieve vpn */
225         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
226         li      r8,MMU_PAGE_4K          /* page size */
227         li      r9,MMU_PAGE_4K          /* actual page size */
228         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
229 .globl htab_call_hpte_insert2
230 htab_call_hpte_insert2:
231         bl      .                       /* Patched by htab_finish_init() */
232         cmpdi   0,r3,0
233         bge+    htab_pte_insert_ok      /* Insertion successful */
234         cmpdi   0,r3,-2                 /* Critical failure */
235         beq-    htab_pte_insert_failure
237         /* Both are full, we need to evict something */
238         mftb    r0
239         /* Pick a random group based on TB */
240         andi.   r0,r0,1
241         mr      r5,r28
242         bne     2f
243         not     r5,r5
244 2:      and     r0,r5,r27
245         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */   
246         /* Call ppc_md.hpte_remove */
247 .globl htab_call_hpte_remove
248 htab_call_hpte_remove:
249         bl      .                       /* Patched by htab_finish_init() */
251         /* Try all again */
252         b       htab_insert_pte 
254 htab_bail_ok:
255         li      r3,0
256         b       htab_bail
258 htab_pte_insert_ok:
259         /* Insert slot number & secondary bit in PTE */
260         rldimi  r30,r3,12,63-15
261                 
262         /* Write out the PTE with a normal write
263          * (maybe add eieio may be good still ?)
264          */
265 htab_write_out_pte:
266         ld      r6,STK_PARAM(R6)(r1)
267         std     r30,0(r6)
268         li      r3, 0
269 htab_bail:
270         ld      r27,STK_REG(R27)(r1)
271         ld      r28,STK_REG(R28)(r1)
272         ld      r29,STK_REG(R29)(r1)
273         ld      r30,STK_REG(R30)(r1)
274         ld      r31,STK_REG(R31)(r1)
275         addi    r1,r1,STACKFRAMESIZE
276         ld      r0,16(r1)
277         mtlr    r0
278         blr
280 htab_modify_pte:
281         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
282         mr      r4,r3
283         rlwinm  r3,r31,32-12,29,31
285         /* Secondary group ? if yes, get a inverted hash value */
286         mr      r5,r28
287         andi.   r0,r31,_PAGE_SECONDARY
288         beq     1f
289         not     r5,r5
291         /* Calculate proper slot value for ppc_md.hpte_updatepp */
292         and     r0,r5,r27
293         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
294         add     r3,r0,r3        /* add slot idx */
296         /* Call ppc_md.hpte_updatepp */
297         mr      r5,r29                  /* vpn */
298         li      r6,MMU_PAGE_4K          /* base page size */
299         li      r7,MMU_PAGE_4K          /* actual page size */
300         ld      r8,STK_PARAM(R9)(r1)    /* segment size */
301         ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
302 .globl htab_call_hpte_updatepp
303 htab_call_hpte_updatepp:
304         bl      .                       /* Patched by htab_finish_init() */
306         /* if we failed because typically the HPTE wasn't really here
307          * we try an insertion. 
308          */
309         cmpdi   0,r3,-1
310         beq-    htab_insert_pte
312         /* Clear the BUSY bit and Write out the PTE */
313         li      r0,_PAGE_BUSY
314         andc    r30,r30,r0
315         b       htab_write_out_pte
317 htab_wrong_access:
318         /* Bail out clearing reservation */
319         stdcx.  r31,0,r6
320         li      r3,1
321         b       htab_bail
323 htab_pte_insert_failure:
324         /* Bail out restoring old PTE */
325         ld      r6,STK_PARAM(R6)(r1)
326         std     r31,0(r6)
327         li      r3,-1
328         b       htab_bail
331 #else /* CONFIG_PPC_64K_PAGES */
334 /*****************************************************************************
335  *                                                                           *
336  *           64K SW & 4K or 64K HW in a 4K segment pages implementation      *
337  *                                                                           *
338  *****************************************************************************/
340 /* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
341  *               pte_t *ptep, unsigned long trap, int local, int ssize,
342  *               int subpg_prot)
343  */
346  * For now, we do NOT implement Admixed pages
347  */
348 _GLOBAL(__hash_page_4K)
349         mflr    r0
350         std     r0,16(r1)
351         stdu    r1,-STACKFRAMESIZE(r1)
352         /* Save all params that we need after a function call */
353         std     r6,STK_PARAM(R6)(r1)
354         std     r8,STK_PARAM(R8)(r1)
355         std     r9,STK_PARAM(R9)(r1)
357         /* Save non-volatile registers.
358          * r31 will hold "old PTE"
359          * r30 is "new PTE"
360          * r29 is vpn
361          * r28 is a hash value
362          * r27 is hashtab mask (maybe dynamic patched instead ?)
363          * r26 is the hidx mask
364          * r25 is the index in combo page
365          */
366         std     r25,STK_REG(R25)(r1)
367         std     r26,STK_REG(R26)(r1)
368         std     r27,STK_REG(R27)(r1)
369         std     r28,STK_REG(R28)(r1)
370         std     r29,STK_REG(R29)(r1)
371         std     r30,STK_REG(R30)(r1)
372         std     r31,STK_REG(R31)(r1)
374         /* Step 1:
375          *
376          * Check permissions, atomically mark the linux PTE busy
377          * and hashed.
378          */
380         ldarx   r31,0,r6
381         /* Check access rights (access & ~(pte_val(*ptep))) */
382         andc.   r0,r4,r31
383         bne-    htab_wrong_access
384         /* Check if PTE is busy */
385         andi.   r0,r31,_PAGE_BUSY
386         /* If so, just bail out and refault if needed. Someone else
387          * is changing this PTE anyway and might hash it.
388          */
389         bne-    htab_bail_ok
390         /* Prepare new PTE value (turn access RW into DIRTY, then
391          * add BUSY and ACCESSED)
392          */
393         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
394         or      r30,r30,r31
395         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
396         oris    r30,r30,_PAGE_COMBO@h
397         /* Write the linux PTE atomically (setting busy) */
398         stdcx.  r30,0,r6
399         bne-    1b
400         isync
402         /* Step 2:
403          *
404          * Insert/Update the HPTE in the hash table. At this point,
405          * r4 (access) is re-useable, we use it for the new HPTE flags
406          */
408         /* Load the hidx index */
409         rldicl  r25,r3,64-12,60
411 BEGIN_FTR_SECTION
412         cmpdi   r9,0                    /* check segment size */
413         bne     3f
414 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
415         /* Calc vpn and put it in r29 */
416         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
417         /*
418          * clrldi r3,r3,64 - SID_SHIFT -->  ea & 0xfffffff
419          * srdi  r28,r3,VPN_SHIFT
420          */
421         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
422         or      r29,r28,r29
423         /*
424          * Calculate hash value for primary slot and store it in r28
425          * r3 = va, r5 = vsid
426          * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
427          */
428         rldicl  r0,r3,64-12,48
429         xor     r28,r5,r0               /* hash */
430         b       4f
432 3:      /* Calc vpn and put it in r29 */
433         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
434         /*
435          * clrldi r3,r3,64 - SID_SHIFT_1T -->  ea & 0xffffffffff
436          * srdi r28,r3,VPN_SHIFT
437          */
438         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
439         or      r29,r28,r29
441         /*
442          * Calculate hash value for primary slot and
443          * store it in r28  for 1T segment
444          * r3 = va, r5 = vsid
445          */
446         sldi    r28,r5,25               /* vsid << 25 */
447         /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */
448         rldicl  r0,r3,64-12,36
449         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
450         xor     r28,r28,r0              /* hash */
452         /* Convert linux PTE bits into HW equivalents */
454 #ifdef CONFIG_PPC_SUBPAGE_PROT
455         andc    r10,r30,r10
456         andi.   r3,r10,0x1fe            /* Get basic set of flags */
457         rlwinm  r0,r10,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
458 #else
459         andi.   r3,r30,0x1fe            /* Get basic set of flags */
460         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
461 #endif
462         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
463         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
464         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
465         andc    r0,r3,r0                /* r0 = pte & ~r0 */
466         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
467         /*
468          * Always add "C" bit for perf. Memory coherence is always enabled
469          */
470         ori     r3,r3,HPTE_R_C | HPTE_R_M
472         /* We eventually do the icache sync here (maybe inline that
473          * code rather than call a C function...)
474          */
475 BEGIN_FTR_SECTION
476         mr      r4,r30
477         mr      r5,r7
478         bl      hash_page_do_lazy_icache
479 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
481         /* At this point, r3 contains new PP bits, save them in
482          * place of "access" in the param area (sic)
483          */
484         std     r3,STK_PARAM(R4)(r1)
486         /* Get htab_hash_mask */
487         ld      r4,htab_hash_mask@got(2)
488         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
490         /* Check if we may already be in the hashtable, in this case, we
491          * go to out-of-line code to try to modify the HPTE. We look for
492          * the bit at (1 >> (index + 32))
493          */
494         rldicl. r0,r31,64-12,48
495         li      r26,0                   /* Default hidx */
496         beq     htab_insert_pte
498         /*
499          * Check if the pte was already inserted into the hash table
500          * as a 64k HW page, and invalidate the 64k HPTE if so.
501          */
502         andis.  r0,r31,_PAGE_COMBO@h
503         beq     htab_inval_old_hpte
505         ld      r6,STK_PARAM(R6)(r1)
506         ori     r26,r6,PTE_PAGE_HIDX_OFFSET /* Load the hidx mask. */
507         ld      r26,0(r26)
508         addi    r5,r25,36               /* Check actual HPTE_SUB bit, this */
509         rldcr.  r0,r31,r5,0             /* must match pgtable.h definition */
510         bne     htab_modify_pte
512 htab_insert_pte:
513         /* real page number in r5, PTE RPN value + index */
514         andis.  r0,r31,_PAGE_4K_PFN@h
515         srdi    r5,r31,PTE_RPN_SHIFT
516         bne-    htab_special_pfn
517         sldi    r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
518         add     r5,r5,r25
519 htab_special_pfn:
520         sldi    r5,r5,HW_PAGE_SHIFT
522         /* Calculate primary group hash */
523         and     r0,r28,r27
524         rldicr  r3,r0,3,63-3            /* r0 = (hash & mask) << 3 */
526         /* Call ppc_md.hpte_insert */
527         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
528         mr      r4,r29                  /* Retrieve vpn */
529         li      r7,0                    /* !bolted, !secondary */
530         li      r8,MMU_PAGE_4K          /* page size */
531         li      r9,MMU_PAGE_4K          /* actual page size */
532         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
533 .globl htab_call_hpte_insert1
534 htab_call_hpte_insert1:
535         bl      .                       /* patched by htab_finish_init() */
536         cmpdi   0,r3,0
537         bge     htab_pte_insert_ok      /* Insertion successful */
538         cmpdi   0,r3,-2                 /* Critical failure */
539         beq-    htab_pte_insert_failure
541         /* Now try secondary slot */
543         /* real page number in r5, PTE RPN value + index */
544         andis.  r0,r31,_PAGE_4K_PFN@h
545         srdi    r5,r31,PTE_RPN_SHIFT
546         bne-    3f
547         sldi    r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
548         add     r5,r5,r25
549 3:      sldi    r5,r5,HW_PAGE_SHIFT
551         /* Calculate secondary group hash */
552         andc    r0,r27,r28
553         rldicr  r3,r0,3,63-3            /* r0 = (~hash & mask) << 3 */
555         /* Call ppc_md.hpte_insert */
556         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
557         mr      r4,r29                  /* Retrieve vpn */
558         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
559         li      r8,MMU_PAGE_4K          /* page size */
560         li      r9,MMU_PAGE_4K          /* actual page size */
561         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
562 .globl htab_call_hpte_insert2
563 htab_call_hpte_insert2:
564         bl      .                       /* patched by htab_finish_init() */
565         cmpdi   0,r3,0
566         bge+    htab_pte_insert_ok      /* Insertion successful */
567         cmpdi   0,r3,-2                 /* Critical failure */
568         beq-    htab_pte_insert_failure
570         /* Both are full, we need to evict something */
571         mftb    r0
572         /* Pick a random group based on TB */
573         andi.   r0,r0,1
574         mr      r5,r28
575         bne     2f
576         not     r5,r5
577 2:      and     r0,r5,r27
578         rldicr  r3,r0,3,63-3            /* r0 = (hash & mask) << 3 */
579         /* Call ppc_md.hpte_remove */
580 .globl htab_call_hpte_remove
581 htab_call_hpte_remove:
582         bl      .                       /* patched by htab_finish_init() */
584         /* Try all again */
585         b       htab_insert_pte
587         /*
588          * Call out to C code to invalidate an 64k HW HPTE that is
589          * useless now that the segment has been switched to 4k pages.
590          */
591 htab_inval_old_hpte:
592         mr      r3,r29                  /* vpn */
593         mr      r4,r31                  /* PTE.pte */
594         li      r5,0                    /* PTE.hidx */
595         li      r6,MMU_PAGE_64K         /* psize */
596         ld      r7,STK_PARAM(R9)(r1)    /* ssize */
597         ld      r8,STK_PARAM(R8)(r1)    /* local */
598         bl      flush_hash_page
599         /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */
600         lis     r0,_PAGE_HPTE_SUB@h
601         ori     r0,r0,_PAGE_HPTE_SUB@l
602         andc    r30,r30,r0
603         b       htab_insert_pte
604         
605 htab_bail_ok:
606         li      r3,0
607         b       htab_bail
609 htab_pte_insert_ok:
610         /* Insert slot number & secondary bit in PTE second half,
611          * clear _PAGE_BUSY and set approriate HPTE slot bit
612          */
613         ld      r6,STK_PARAM(R6)(r1)
614         li      r0,_PAGE_BUSY
615         andc    r30,r30,r0
616         /* HPTE SUB bit */
617         li      r0,1
618         subfic  r5,r25,27               /* Must match bit position in */
619         sld     r0,r0,r5                /* pgtable.h */
620         or      r30,r30,r0
621         /* hindx */
622         sldi    r5,r25,2
623         sld     r3,r3,r5
624         li      r4,0xf
625         sld     r4,r4,r5
626         andc    r26,r26,r4
627         or      r26,r26,r3
628         ori     r5,r6,PTE_PAGE_HIDX_OFFSET
629         std     r26,0(r5)
630         lwsync
631         std     r30,0(r6)
632         li      r3, 0
633 htab_bail:
634         ld      r25,STK_REG(R25)(r1)
635         ld      r26,STK_REG(R26)(r1)
636         ld      r27,STK_REG(R27)(r1)
637         ld      r28,STK_REG(R28)(r1)
638         ld      r29,STK_REG(R29)(r1)
639         ld      r30,STK_REG(R30)(r1)
640         ld      r31,STK_REG(R31)(r1)
641         addi    r1,r1,STACKFRAMESIZE
642         ld      r0,16(r1)
643         mtlr    r0
644         blr
646 htab_modify_pte:
647         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
648         mr      r4,r3
649         sldi    r5,r25,2
650         srd     r3,r26,r5
652         /* Secondary group ? if yes, get a inverted hash value */
653         mr      r5,r28
654         andi.   r0,r3,0x8 /* page secondary ? */
655         beq     1f
656         not     r5,r5
657 1:      andi.   r3,r3,0x7 /* extract idx alone */
659         /* Calculate proper slot value for ppc_md.hpte_updatepp */
660         and     r0,r5,r27
661         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
662         add     r3,r0,r3        /* add slot idx */
664         /* Call ppc_md.hpte_updatepp */
665         mr      r5,r29                  /* vpn */
666         li      r6,MMU_PAGE_4K          /* base page size */
667         li      r7,MMU_PAGE_4K          /* actual page size */
668         ld      r8,STK_PARAM(R9)(r1)    /* segment size */
669         ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
670 .globl htab_call_hpte_updatepp
671 htab_call_hpte_updatepp:
672         bl      .                       /* patched by htab_finish_init() */
674         /* if we failed because typically the HPTE wasn't really here
675          * we try an insertion.
676          */
677         cmpdi   0,r3,-1
678         beq-    htab_insert_pte
680         /* Clear the BUSY bit and Write out the PTE */
681         li      r0,_PAGE_BUSY
682         andc    r30,r30,r0
683         ld      r6,STK_PARAM(R6)(r1)
684         std     r30,0(r6)
685         li      r3,0
686         b       htab_bail
688 htab_wrong_access:
689         /* Bail out clearing reservation */
690         stdcx.  r31,0,r6
691         li      r3,1
692         b       htab_bail
694 htab_pte_insert_failure:
695         /* Bail out restoring old PTE */
696         ld      r6,STK_PARAM(R6)(r1)
697         std     r31,0(r6)
698         li      r3,-1
699         b       htab_bail
701 #endif /* CONFIG_PPC_64K_PAGES */
703 #ifdef CONFIG_PPC_HAS_HASH_64K
705 /*****************************************************************************
706  *                                                                           *
707  *           64K SW & 64K HW in a 64K segment pages implementation           *
708  *                                                                           *
709  *****************************************************************************/
711 _GLOBAL(__hash_page_64K)
712         mflr    r0
713         std     r0,16(r1)
714         stdu    r1,-STACKFRAMESIZE(r1)
715         /* Save all params that we need after a function call */
716         std     r6,STK_PARAM(R6)(r1)
717         std     r8,STK_PARAM(R8)(r1)
718         std     r9,STK_PARAM(R9)(r1)
720         /* Save non-volatile registers.
721          * r31 will hold "old PTE"
722          * r30 is "new PTE"
723          * r29 is vpn
724          * r28 is a hash value
725          * r27 is hashtab mask (maybe dynamic patched instead ?)
726          */
727         std     r27,STK_REG(R27)(r1)
728         std     r28,STK_REG(R28)(r1)
729         std     r29,STK_REG(R29)(r1)
730         std     r30,STK_REG(R30)(r1)
731         std     r31,STK_REG(R31)(r1)
733         /* Step 1:
734          *
735          * Check permissions, atomically mark the linux PTE busy
736          * and hashed.
737          */
739         ldarx   r31,0,r6
740         /* Check access rights (access & ~(pte_val(*ptep))) */
741         andc.   r0,r4,r31
742         bne-    ht64_wrong_access
743         /* Check if PTE is busy */
744         andi.   r0,r31,_PAGE_BUSY
745         /* If so, just bail out and refault if needed. Someone else
746          * is changing this PTE anyway and might hash it.
747          */
748         bne-    ht64_bail_ok
749 BEGIN_FTR_SECTION
750         /* Check if PTE has the cache-inhibit bit set */
751         andi.   r0,r31,_PAGE_NO_CACHE
752         /* If so, bail out and refault as a 4k page */
753         bne-    ht64_bail_ok
754 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)
755         /* Prepare new PTE value (turn access RW into DIRTY, then
756          * add BUSY and ACCESSED)
757          */
758         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
759         or      r30,r30,r31
760         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
761         /* Write the linux PTE atomically (setting busy) */
762         stdcx.  r30,0,r6
763         bne-    1b
764         isync
766         /* Step 2:
767          *
768          * Insert/Update the HPTE in the hash table. At this point,
769          * r4 (access) is re-useable, we use it for the new HPTE flags
770          */
772 BEGIN_FTR_SECTION
773         cmpdi   r9,0                    /* check segment size */
774         bne     3f
775 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
776         /* Calc vpn and put it in r29 */
777         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
778         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
779         or      r29,r28,r29
781         /* Calculate hash value for primary slot and store it in r28
782          * r3 = va, r5 = vsid
783          * r0 = (va >> 16) & ((1ul << (28 - 16)) -1)
784          */
785         rldicl  r0,r3,64-16,52
786         xor     r28,r5,r0               /* hash */
787         b       4f
789 3:      /* Calc vpn and put it in r29 */
790         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
791         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
792         or      r29,r28,r29
793         /*
794          * calculate hash value for primary slot and
795          * store it in r28 for 1T segment
796          * r3 = va, r5 = vsid
797          */
798         sldi    r28,r5,25               /* vsid << 25 */
799         /* r0 = (va >> 16) & ((1ul << (40 - 16)) -1) */
800         rldicl  r0,r3,64-16,40
801         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
802         xor     r28,r28,r0              /* hash */
804         /* Convert linux PTE bits into HW equivalents */
805 4:      andi.   r3,r30,0x1fe            /* Get basic set of flags */
806         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
807         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
808         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
809         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
810         andc    r0,r30,r0               /* r0 = pte & ~r0 */
811         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
812         /*
813          * Always add "C" bit for perf. Memory coherence is always enabled
814          */
815         ori     r3,r3,HPTE_R_C | HPTE_R_M
817         /* We eventually do the icache sync here (maybe inline that
818          * code rather than call a C function...)
819          */
820 BEGIN_FTR_SECTION
821         mr      r4,r30
822         mr      r5,r7
823         bl      hash_page_do_lazy_icache
824 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
826         /* At this point, r3 contains new PP bits, save them in
827          * place of "access" in the param area (sic)
828          */
829         std     r3,STK_PARAM(R4)(r1)
831         /* Get htab_hash_mask */
832         ld      r4,htab_hash_mask@got(2)
833         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
835         /* Check if we may already be in the hashtable, in this case, we
836          * go to out-of-line code to try to modify the HPTE
837          */
838         rldicl. r0,r31,64-12,48
839         bne     ht64_modify_pte
841 ht64_insert_pte:
842         /* Clear hpte bits in new pte (we also clear BUSY btw) and
843          * add _PAGE_HPTE_SUB0
844          */
845         lis     r0,_PAGE_HPTEFLAGS@h
846         ori     r0,r0,_PAGE_HPTEFLAGS@l
847         andc    r30,r30,r0
848 #ifdef CONFIG_PPC_64K_PAGES
849         oris    r30,r30,_PAGE_HPTE_SUB0@h
850 #else
851         ori     r30,r30,_PAGE_HASHPTE
852 #endif
853         /* Phyical address in r5 */
854         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
855         sldi    r5,r5,PAGE_SHIFT
857         /* Calculate primary group hash */
858         and     r0,r28,r27
859         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */
861         /* Call ppc_md.hpte_insert */
862         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
863         mr      r4,r29                  /* Retrieve vpn */
864         li      r7,0                    /* !bolted, !secondary */
865         li      r8,MMU_PAGE_64K
866         li      r9,MMU_PAGE_64K         /* actual page size */
867         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
868 .globl ht64_call_hpte_insert1
869 ht64_call_hpte_insert1:
870         bl      .                       /* patched by htab_finish_init() */
871         cmpdi   0,r3,0
872         bge     ht64_pte_insert_ok      /* Insertion successful */
873         cmpdi   0,r3,-2                 /* Critical failure */
874         beq-    ht64_pte_insert_failure
876         /* Now try secondary slot */
878         /* Phyical address in r5 */
879         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
880         sldi    r5,r5,PAGE_SHIFT
882         /* Calculate secondary group hash */
883         andc    r0,r27,r28
884         rldicr  r3,r0,3,63-3    /* r0 = (~hash & mask) << 3 */
886         /* Call ppc_md.hpte_insert */
887         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
888         mr      r4,r29                  /* Retrieve vpn */
889         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
890         li      r8,MMU_PAGE_64K
891         li      r9,MMU_PAGE_64K         /* actual page size */
892         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
893 .globl ht64_call_hpte_insert2
894 ht64_call_hpte_insert2:
895         bl      .                       /* patched by htab_finish_init() */
896         cmpdi   0,r3,0
897         bge+    ht64_pte_insert_ok      /* Insertion successful */
898         cmpdi   0,r3,-2                 /* Critical failure */
899         beq-    ht64_pte_insert_failure
901         /* Both are full, we need to evict something */
902         mftb    r0
903         /* Pick a random group based on TB */
904         andi.   r0,r0,1
905         mr      r5,r28
906         bne     2f
907         not     r5,r5
908 2:      and     r0,r5,r27
909         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */
910         /* Call ppc_md.hpte_remove */
911 .globl ht64_call_hpte_remove
912 ht64_call_hpte_remove:
913         bl      .                       /* patched by htab_finish_init() */
915         /* Try all again */
916         b       ht64_insert_pte
918 ht64_bail_ok:
919         li      r3,0
920         b       ht64_bail
922 ht64_pte_insert_ok:
923         /* Insert slot number & secondary bit in PTE */
924         rldimi  r30,r3,12,63-15
926         /* Write out the PTE with a normal write
927          * (maybe add eieio may be good still ?)
928          */
929 ht64_write_out_pte:
930         ld      r6,STK_PARAM(R6)(r1)
931         std     r30,0(r6)
932         li      r3, 0
933 ht64_bail:
934         ld      r27,STK_REG(R27)(r1)
935         ld      r28,STK_REG(R28)(r1)
936         ld      r29,STK_REG(R29)(r1)
937         ld      r30,STK_REG(R30)(r1)
938         ld      r31,STK_REG(R31)(r1)
939         addi    r1,r1,STACKFRAMESIZE
940         ld      r0,16(r1)
941         mtlr    r0
942         blr
944 ht64_modify_pte:
945         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
946         mr      r4,r3
947         rlwinm  r3,r31,32-12,29,31
949         /* Secondary group ? if yes, get a inverted hash value */
950         mr      r5,r28
951         andi.   r0,r31,_PAGE_F_SECOND
952         beq     1f
953         not     r5,r5
955         /* Calculate proper slot value for ppc_md.hpte_updatepp */
956         and     r0,r5,r27
957         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
958         add     r3,r0,r3        /* add slot idx */
960         /* Call ppc_md.hpte_updatepp */
961         mr      r5,r29                  /* vpn */
962         li      r6,MMU_PAGE_64K         /* base page size */
963         li      r7,MMU_PAGE_64K         /* actual page size */
964         ld      r8,STK_PARAM(R9)(r1)    /* segment size */
965         ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
966 .globl ht64_call_hpte_updatepp
967 ht64_call_hpte_updatepp:
968         bl      .                       /* patched by htab_finish_init() */
970         /* if we failed because typically the HPTE wasn't really here
971          * we try an insertion.
972          */
973         cmpdi   0,r3,-1
974         beq-    ht64_insert_pte
976         /* Clear the BUSY bit and Write out the PTE */
977         li      r0,_PAGE_BUSY
978         andc    r30,r30,r0
979         b       ht64_write_out_pte
981 ht64_wrong_access:
982         /* Bail out clearing reservation */
983         stdcx.  r31,0,r6
984         li      r3,1
985         b       ht64_bail
987 ht64_pte_insert_failure:
988         /* Bail out restoring old PTE */
989         ld      r6,STK_PARAM(R6)(r1)
990         std     r31,0(r6)
991         li      r3,-1
992         b       ht64_bail
995 #endif /* CONFIG_PPC_HAS_HASH_64K */
998 /*****************************************************************************
999  *                                                                           *
1000  *           Huge pages implementation is in hugetlbpage.c                   *
1001  *                                                                           *
1002  *****************************************************************************/