blob: e935edd6b72b44645ddf9a6d82af9c8e0b02c13b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ppc64 MMU hashtable management routines
3 *
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +11004 * (c) Copyright IBM Corp. 2003, 2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
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
Paul Mackerrasab1f9da2005-10-10 21:58:35 +100013#include <asm/reg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#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>
Sam Ravnborg0013a852005-09-09 20:57:26 +020019#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#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#define STACKFRAMESIZE 256
38
39/* Save parameters offsets */
40#define STK_PARM(i) (STACKFRAMESIZE + 48 + ((i)-3)*8)
41
42/* Save non-volatile offsets */
43#define STK_REG(i) (112 + ((i)-14)*8)
44
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +110045
46#ifndef CONFIG_PPC_64K_PAGES
47
48/*****************************************************************************
49 * *
50 * 4K SW & 4K HW pages implementation *
51 * *
52 *****************************************************************************/
53
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055/*
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +110056 * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
Paul Mackerras1189be62007-10-11 20:37:10 +100057 * pte_t *ptep, unsigned long trap, int local, int ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 *
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +110059 * Adds a 4K page to the hash table in a segment of 4K pages only
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 */
61
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +110062_GLOBAL(__hash_page_4K)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 mflr r0
64 std r0,16(r1)
65 stdu r1,-STACKFRAMESIZE(r1)
66 /* Save all params that we need after a function call */
67 std r6,STK_PARM(r6)(r1)
68 std r8,STK_PARM(r8)(r1)
Paul Mackerras1189be62007-10-11 20:37:10 +100069 std r9,STK_PARM(r9)(r1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71 /* Add _PAGE_PRESENT to access */
72 ori r4,r4,_PAGE_PRESENT
73
74 /* Save non-volatile registers.
75 * r31 will hold "old PTE"
76 * r30 is "new PTE"
77 * r29 is "va"
78 * r28 is a hash value
79 * r27 is hashtab mask (maybe dynamic patched instead ?)
80 */
81 std r27,STK_REG(r27)(r1)
82 std r28,STK_REG(r28)(r1)
83 std r29,STK_REG(r29)(r1)
84 std r30,STK_REG(r30)(r1)
85 std r31,STK_REG(r31)(r1)
86
87 /* Step 1:
88 *
89 * Check permissions, atomically mark the linux PTE busy
90 * and hashed.
91 */
921:
93 ldarx r31,0,r6
94 /* Check access rights (access & ~(pte_val(*ptep))) */
95 andc. r0,r4,r31
96 bne- htab_wrong_access
97 /* Check if PTE is busy */
98 andi. r0,r31,_PAGE_BUSY
Olof Johanssond03853d2005-05-01 08:58:45 -070099 /* If so, just bail out and refault if needed. Someone else
100 * is changing this PTE anyway and might hash it.
101 */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100102 bne- htab_bail_ok
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 /* Prepare new PTE value (turn access RW into DIRTY, then
105 * add BUSY,HASHPTE and ACCESSED)
106 */
107 rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
108 or r30,r30,r31
109 ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
110 /* Write the linux PTE atomically (setting busy) */
111 stdcx. r30,0,r6
112 bne- 1b
113 isync
114
115 /* Step 2:
116 *
117 * Insert/Update the HPTE in the hash table. At this point,
118 * r4 (access) is re-useable, we use it for the new HPTE flags
119 */
120
Paul Mackerras1189be62007-10-11 20:37:10 +1000121BEGIN_FTR_SECTION
122 cmpdi r9,0 /* check segment size */
123 bne 3f
124END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 /* Calc va and put it in r29 */
126 rldicr r29,r5,28,63-28
127 rldicl r3,r3,0,36
128 or r29,r3,r29
129
130 /* Calculate hash value for primary slot and store it in r28 */
131 rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */
132 rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */
133 xor r28,r5,r0
Paul Mackerras1189be62007-10-11 20:37:10 +1000134 b 4f
135
1363: /* Calc VA and hash in r29 and r28 for 1T segment */
137 sldi r29,r5,40 /* vsid << 40 */
138 clrldi r3,r3,24 /* ea & 0xffffffffff */
139 rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */
140 clrldi r5,r5,40 /* vsid & 0xffffff */
141 rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */
142 xor r28,r28,r5
143 or r29,r3,r29 /* VA */
144 xor r28,r28,r0 /* hash */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146 /* Convert linux PTE bits into HW equivalents */
Paul Mackerras1189be62007-10-11 20:37:10 +10001474: andi. r3,r30,0x1fe /* Get basic set of flags */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100148 xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
150 rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100151 and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 andc r0,r30,r0 /* r0 = pte & ~r0 */
153 rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
Benjamin Herrenschmidtc5cf0e32006-05-30 14:14:19 +1000154 ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 /* We eventually do the icache sync here (maybe inline that
157 * code rather than call a C function...)
158 */
159BEGIN_FTR_SECTION
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 mr r4,r30
161 mr r5,r7
162 bl .hash_page_do_lazy_icache
David Gibson8913ca12005-07-27 15:47:23 +1000163END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
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_PARM(r4)(r1)
169
170 /* Get htab_hash_mask */
171 ld r4,htab_hash_mask@got(2)
172 ld r27,0(r4) /* htab_hash_mask -> r27 */
173
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
179
180htab_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
188
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100189 /* physical address r5 */
190 rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
191 sldi r5,r5,PAGE_SHIFT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193 /* Calculate primary group hash */
194 and r0,r28,r27
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100195 rldicr r3,r0,3,63-3 /* r3 = (hash & mask) << 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197 /* Call ppc_md.hpte_insert */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100198 ld r6,STK_PARM(r4)(r1) /* Retreive new pp bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 mr r4,r29 /* Retreive va */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100200 li r7,0 /* !bolted, !secondary */
201 li r8,MMU_PAGE_4K /* page size */
Paul Mackerras1189be62007-10-11 20:37:10 +1000202 ld r9,STK_PARM(r9)(r1) /* segment size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203_GLOBAL(htab_call_hpte_insert1)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100204 bl . /* Patched by htab_finish_init() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 cmpdi 0,r3,0
206 bge htab_pte_insert_ok /* Insertion successful */
207 cmpdi 0,r3,-2 /* Critical failure */
208 beq- htab_pte_insert_failure
209
210 /* Now try secondary slot */
211
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100212 /* physical address r5 */
213 rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
214 sldi r5,r5,PAGE_SHIFT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 /* Calculate secondary group hash */
217 andc r0,r27,r28
218 rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */
219
220 /* Call ppc_md.hpte_insert */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100221 ld r6,STK_PARM(r4)(r1) /* Retreive new pp bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 mr r4,r29 /* Retreive va */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100223 li r7,HPTE_V_SECONDARY /* !bolted, secondary */
224 li r8,MMU_PAGE_4K /* page size */
Paul Mackerras1189be62007-10-11 20:37:10 +1000225 ld r9,STK_PARM(r9)(r1) /* segment size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226_GLOBAL(htab_call_hpte_insert2)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100227 bl . /* Patched by htab_finish_init() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 cmpdi 0,r3,0
229 bge+ htab_pte_insert_ok /* Insertion successful */
230 cmpdi 0,r3,-2 /* Critical failure */
231 beq- htab_pte_insert_failure
232
233 /* Both are full, we need to evict something */
234 mftb r0
235 /* Pick a random group based on TB */
236 andi. r0,r0,1
237 mr r5,r28
238 bne 2f
239 not r5,r5
2402: and r0,r5,r27
241 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
242 /* Call ppc_md.hpte_remove */
243_GLOBAL(htab_call_hpte_remove)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100244 bl . /* Patched by htab_finish_init() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 /* Try all again */
247 b htab_insert_pte
248
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100249htab_bail_ok:
Olof Johanssond03853d2005-05-01 08:58:45 -0700250 li r3,0
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100251 b htab_bail
Olof Johanssond03853d2005-05-01 08:58:45 -0700252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253htab_pte_insert_ok:
254 /* Insert slot number & secondary bit in PTE */
255 rldimi r30,r3,12,63-15
256
257 /* Write out the PTE with a normal write
258 * (maybe add eieio may be good still ?)
259 */
260htab_write_out_pte:
261 ld r6,STK_PARM(r6)(r1)
262 std r30,0(r6)
263 li r3, 0
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100264htab_bail:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 ld r27,STK_REG(r27)(r1)
266 ld r28,STK_REG(r28)(r1)
267 ld r29,STK_REG(r29)(r1)
268 ld r30,STK_REG(r30)(r1)
269 ld r31,STK_REG(r31)(r1)
270 addi r1,r1,STACKFRAMESIZE
271 ld r0,16(r1)
272 mtlr r0
273 blr
274
275htab_modify_pte:
276 /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
277 mr r4,r3
278 rlwinm r3,r31,32-12,29,31
279
280 /* Secondary group ? if yes, get a inverted hash value */
281 mr r5,r28
282 andi. r0,r31,_PAGE_SECONDARY
283 beq 1f
284 not r5,r5
2851:
286 /* Calculate proper slot value for ppc_md.hpte_updatepp */
287 and r0,r5,r27
288 rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */
289 add r3,r0,r3 /* add slot idx */
290
291 /* Call ppc_md.hpte_updatepp */
292 mr r5,r29 /* va */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100293 li r6,MMU_PAGE_4K /* page size */
Paul Mackerras1189be62007-10-11 20:37:10 +1000294 ld r7,STK_PARM(r9)(r1) /* segment size */
295 ld r8,STK_PARM(r8)(r1) /* get "local" param */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296_GLOBAL(htab_call_hpte_updatepp)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100297 bl . /* Patched by htab_finish_init() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 /* if we failed because typically the HPTE wasn't really here
300 * we try an insertion.
301 */
302 cmpdi 0,r3,-1
303 beq- htab_insert_pte
304
305 /* Clear the BUSY bit and Write out the PTE */
306 li r0,_PAGE_BUSY
307 andc r30,r30,r0
308 b htab_write_out_pte
309
310htab_wrong_access:
311 /* Bail out clearing reservation */
312 stdcx. r31,0,r6
313 li r3,1
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100314 b htab_bail
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316htab_pte_insert_failure:
317 /* Bail out restoring old PTE */
318 ld r6,STK_PARM(r6)(r1)
319 std r31,0(r6)
320 li r3,-1
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100321 b htab_bail
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100324#else /* CONFIG_PPC_64K_PAGES */
325
326
327/*****************************************************************************
328 * *
329 * 64K SW & 4K or 64K HW in a 4K segment pages implementation *
330 * *
331 *****************************************************************************/
332
333/* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
Benjamin Herrenschmidtf6ab0b92007-10-29 12:05:18 +1100334 * pte_t *ptep, unsigned long trap, int local, int ssize)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100335 */
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_PARM(r6)(r1)
346 std r8,STK_PARM(r8)(r1)
Paul Mackerras1189be62007-10-11 20:37:10 +1000347 std r9,STK_PARM(r9)(r1)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100348
349 /* Add _PAGE_PRESENT to access */
350 ori r4,r4,_PAGE_PRESENT
351
352 /* Save non-volatile registers.
353 * r31 will hold "old PTE"
354 * r30 is "new PTE"
355 * r29 is "va"
356 * r28 is a hash value
357 * r27 is hashtab mask (maybe dynamic patched instead ?)
358 * r26 is the hidx mask
359 * r25 is the index in combo page
360 */
361 std r25,STK_REG(r25)(r1)
362 std r26,STK_REG(r26)(r1)
363 std r27,STK_REG(r27)(r1)
364 std r28,STK_REG(r28)(r1)
365 std r29,STK_REG(r29)(r1)
366 std r30,STK_REG(r30)(r1)
367 std r31,STK_REG(r31)(r1)
368
369 /* Step 1:
370 *
371 * Check permissions, atomically mark the linux PTE busy
372 * and hashed.
373 */
3741:
375 ldarx r31,0,r6
376 /* Check access rights (access & ~(pte_val(*ptep))) */
377 andc. r0,r4,r31
378 bne- htab_wrong_access
379 /* Check if PTE is busy */
380 andi. r0,r31,_PAGE_BUSY
381 /* If so, just bail out and refault if needed. Someone else
382 * is changing this PTE anyway and might hash it.
383 */
384 bne- htab_bail_ok
385 /* Prepare new PTE value (turn access RW into DIRTY, then
386 * add BUSY and ACCESSED)
387 */
388 rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
389 or r30,r30,r31
390 ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
Paul Mackerrasbf72aeb2006-06-15 10:45:18 +1000391 oris r30,r30,_PAGE_COMBO@h
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100392 /* Write the linux PTE atomically (setting busy) */
393 stdcx. r30,0,r6
394 bne- 1b
395 isync
396
397 /* Step 2:
398 *
399 * Insert/Update the HPTE in the hash table. At this point,
400 * r4 (access) is re-useable, we use it for the new HPTE flags
401 */
402
403 /* Load the hidx index */
404 rldicl r25,r3,64-12,60
405
Paul Mackerras1189be62007-10-11 20:37:10 +1000406BEGIN_FTR_SECTION
407 cmpdi r9,0 /* check segment size */
408 bne 3f
409END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100410 /* Calc va and put it in r29 */
411 rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */
412 rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */
Paul Mackerras1189be62007-10-11 20:37:10 +1000413 or r29,r3,r29 /* r29 = va */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100414
415 /* Calculate hash value for primary slot and store it in r28 */
416 rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */
417 rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */
418 xor r28,r5,r0
Paul Mackerras1189be62007-10-11 20:37:10 +1000419 b 4f
420
4213: /* Calc VA and hash in r29 and r28 for 1T segment */
422 sldi r29,r5,40 /* vsid << 40 */
423 clrldi r3,r3,24 /* ea & 0xffffffffff */
424 rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */
425 clrldi r5,r5,40 /* vsid & 0xffffff */
426 rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */
427 xor r28,r28,r5
428 or r29,r3,r29 /* VA */
429 xor r28,r28,r0 /* hash */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100430
431 /* Convert linux PTE bits into HW equivalents */
Paul Mackerras1189be62007-10-11 20:37:10 +10004324: andi. r3,r30,0x1fe /* Get basic set of flags */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100433 xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */
434 rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
435 rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */
436 and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
437 andc r0,r30,r0 /* r0 = pte & ~r0 */
438 rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
Benjamin Herrenschmidtc5cf0e32006-05-30 14:14:19 +1000439 ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100440
441 /* We eventually do the icache sync here (maybe inline that
442 * code rather than call a C function...)
443 */
444BEGIN_FTR_SECTION
445 mr r4,r30
446 mr r5,r7
447 bl .hash_page_do_lazy_icache
448END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
449
450 /* At this point, r3 contains new PP bits, save them in
451 * place of "access" in the param area (sic)
452 */
453 std r3,STK_PARM(r4)(r1)
454
455 /* Get htab_hash_mask */
456 ld r4,htab_hash_mask@got(2)
457 ld r27,0(r4) /* htab_hash_mask -> r27 */
458
459 /* Check if we may already be in the hashtable, in this case, we
460 * go to out-of-line code to try to modify the HPTE. We look for
461 * the bit at (1 >> (index + 32))
462 */
463 andi. r0,r31,_PAGE_HASHPTE
464 li r26,0 /* Default hidx */
465 beq htab_insert_pte
Paul Mackerrasbf72aeb2006-06-15 10:45:18 +1000466
467 /*
468 * Check if the pte was already inserted into the hash table
469 * as a 64k HW page, and invalidate the 64k HPTE if so.
470 */
471 andis. r0,r31,_PAGE_COMBO@h
472 beq htab_inval_old_hpte
473
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100474 ld r6,STK_PARM(r6)(r1)
475 ori r26,r6,0x8000 /* Load the hidx mask */
476 ld r26,0(r26)
477 addi r5,r25,36 /* Check actual HPTE_SUB bit, this */
478 rldcr. r0,r31,r5,0 /* must match pgtable.h definition */
479 bne htab_modify_pte
480
481htab_insert_pte:
482 /* real page number in r5, PTE RPN value + index */
Paul Mackerras721151d2007-04-03 21:24:02 +1000483 andis. r0,r31,_PAGE_4K_PFN@h
484 srdi r5,r31,PTE_RPN_SHIFT
485 bne- htab_special_pfn
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100486 sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
487 add r5,r5,r25
Paul Mackerras721151d2007-04-03 21:24:02 +1000488htab_special_pfn:
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100489 sldi r5,r5,HW_PAGE_SHIFT
490
491 /* Calculate primary group hash */
492 and r0,r28,r27
493 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
494
495 /* Call ppc_md.hpte_insert */
496 ld r6,STK_PARM(r4)(r1) /* Retreive new pp bits */
497 mr r4,r29 /* Retreive va */
498 li r7,0 /* !bolted, !secondary */
499 li r8,MMU_PAGE_4K /* page size */
Paul Mackerras1189be62007-10-11 20:37:10 +1000500 ld r9,STK_PARM(r9)(r1) /* segment size */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100501_GLOBAL(htab_call_hpte_insert1)
502 bl . /* patched by htab_finish_init() */
503 cmpdi 0,r3,0
504 bge htab_pte_insert_ok /* Insertion successful */
505 cmpdi 0,r3,-2 /* Critical failure */
506 beq- htab_pte_insert_failure
507
508 /* Now try secondary slot */
509
510 /* real page number in r5, PTE RPN value + index */
Paul Mackerras430404e2007-08-03 19:16:11 +1000511 andis. r0,r31,_PAGE_4K_PFN@h
512 srdi r5,r31,PTE_RPN_SHIFT
513 bne- 3f
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100514 sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
515 add r5,r5,r25
Paul Mackerras430404e2007-08-03 19:16:11 +10005163: sldi r5,r5,HW_PAGE_SHIFT
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100517
518 /* Calculate secondary group hash */
519 andc r0,r27,r28
520 rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */
521
522 /* Call ppc_md.hpte_insert */
523 ld r6,STK_PARM(r4)(r1) /* Retreive new pp bits */
524 mr r4,r29 /* Retreive va */
525 li r7,HPTE_V_SECONDARY /* !bolted, secondary */
526 li r8,MMU_PAGE_4K /* page size */
Paul Mackerras1189be62007-10-11 20:37:10 +1000527 ld r9,STK_PARM(r9)(r1) /* segment size */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100528_GLOBAL(htab_call_hpte_insert2)
529 bl . /* patched by htab_finish_init() */
530 cmpdi 0,r3,0
531 bge+ htab_pte_insert_ok /* Insertion successful */
532 cmpdi 0,r3,-2 /* Critical failure */
533 beq- htab_pte_insert_failure
534
535 /* Both are full, we need to evict something */
536 mftb r0
537 /* Pick a random group based on TB */
538 andi. r0,r0,1
539 mr r5,r28
540 bne 2f
541 not r5,r5
5422: and r0,r5,r27
543 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
544 /* Call ppc_md.hpte_remove */
545_GLOBAL(htab_call_hpte_remove)
546 bl . /* patched by htab_finish_init() */
547
548 /* Try all again */
549 b htab_insert_pte
550
Paul Mackerrasbf72aeb2006-06-15 10:45:18 +1000551 /*
552 * Call out to C code to invalidate an 64k HW HPTE that is
553 * useless now that the segment has been switched to 4k pages.
554 */
555htab_inval_old_hpte:
556 mr r3,r29 /* virtual addr */
557 mr r4,r31 /* PTE.pte */
558 li r5,0 /* PTE.hidx */
559 li r6,MMU_PAGE_64K /* psize */
Benjamin Herrenschmidtf6ab0b92007-10-29 12:05:18 +1100560 ld r7,STK_PARM(r9)(r1) /* ssize */
561 ld r8,STK_PARM(r8)(r1) /* local */
Paul Mackerrasbf72aeb2006-06-15 10:45:18 +1000562 bl .flush_hash_page
563 b htab_insert_pte
564
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100565htab_bail_ok:
566 li r3,0
567 b htab_bail
568
569htab_pte_insert_ok:
570 /* Insert slot number & secondary bit in PTE second half,
571 * clear _PAGE_BUSY and set approriate HPTE slot bit
572 */
573 ld r6,STK_PARM(r6)(r1)
574 li r0,_PAGE_BUSY
575 andc r30,r30,r0
576 /* HPTE SUB bit */
577 li r0,1
578 subfic r5,r25,27 /* Must match bit position in */
579 sld r0,r0,r5 /* pgtable.h */
580 or r30,r30,r0
581 /* hindx */
582 sldi r5,r25,2
583 sld r3,r3,r5
584 li r4,0xf
585 sld r4,r4,r5
586 andc r26,r26,r4
587 or r26,r26,r3
588 ori r5,r6,0x8000
589 std r26,0(r5)
590 lwsync
591 std r30,0(r6)
592 li r3, 0
593htab_bail:
594 ld r25,STK_REG(r25)(r1)
595 ld r26,STK_REG(r26)(r1)
596 ld r27,STK_REG(r27)(r1)
597 ld r28,STK_REG(r28)(r1)
598 ld r29,STK_REG(r29)(r1)
599 ld r30,STK_REG(r30)(r1)
600 ld r31,STK_REG(r31)(r1)
601 addi r1,r1,STACKFRAMESIZE
602 ld r0,16(r1)
603 mtlr r0
604 blr
605
606htab_modify_pte:
607 /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
608 mr r4,r3
609 sldi r5,r25,2
610 srd r3,r26,r5
611
612 /* Secondary group ? if yes, get a inverted hash value */
613 mr r5,r28
614 andi. r0,r3,0x8 /* page secondary ? */
615 beq 1f
616 not r5,r5
6171: andi. r3,r3,0x7 /* extract idx alone */
618
619 /* Calculate proper slot value for ppc_md.hpte_updatepp */
620 and r0,r5,r27
621 rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */
622 add r3,r0,r3 /* add slot idx */
623
624 /* Call ppc_md.hpte_updatepp */
625 mr r5,r29 /* va */
626 li r6,MMU_PAGE_4K /* page size */
Paul Mackerras1189be62007-10-11 20:37:10 +1000627 ld r7,STK_PARM(r9)(r1) /* segment size */
628 ld r8,STK_PARM(r8)(r1) /* get "local" param */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100629_GLOBAL(htab_call_hpte_updatepp)
630 bl . /* patched by htab_finish_init() */
631
632 /* if we failed because typically the HPTE wasn't really here
633 * we try an insertion.
634 */
635 cmpdi 0,r3,-1
636 beq- htab_insert_pte
637
638 /* Clear the BUSY bit and Write out the PTE */
639 li r0,_PAGE_BUSY
640 andc r30,r30,r0
641 ld r6,STK_PARM(r6)(r1)
642 std r30,0(r6)
643 li r3,0
644 b htab_bail
645
646htab_wrong_access:
647 /* Bail out clearing reservation */
648 stdcx. r31,0,r6
649 li r3,1
650 b htab_bail
651
652htab_pte_insert_failure:
653 /* Bail out restoring old PTE */
654 ld r6,STK_PARM(r6)(r1)
655 std r31,0(r6)
656 li r3,-1
657 b htab_bail
658
Benjamin Herrenschmidt16c2d472007-05-08 16:27:28 +1000659#endif /* CONFIG_PPC_64K_PAGES */
660
661#ifdef CONFIG_PPC_HAS_HASH_64K
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100662
663/*****************************************************************************
664 * *
665 * 64K SW & 64K HW in a 64K segment pages implementation *
666 * *
667 *****************************************************************************/
668
669_GLOBAL(__hash_page_64K)
670 mflr r0
671 std r0,16(r1)
672 stdu r1,-STACKFRAMESIZE(r1)
673 /* Save all params that we need after a function call */
674 std r6,STK_PARM(r6)(r1)
675 std r8,STK_PARM(r8)(r1)
Paul Mackerras1189be62007-10-11 20:37:10 +1000676 std r9,STK_PARM(r9)(r1)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100677
678 /* Add _PAGE_PRESENT to access */
679 ori r4,r4,_PAGE_PRESENT
680
681 /* Save non-volatile registers.
682 * r31 will hold "old PTE"
683 * r30 is "new PTE"
684 * r29 is "va"
685 * r28 is a hash value
686 * r27 is hashtab mask (maybe dynamic patched instead ?)
687 */
688 std r27,STK_REG(r27)(r1)
689 std r28,STK_REG(r28)(r1)
690 std r29,STK_REG(r29)(r1)
691 std r30,STK_REG(r30)(r1)
692 std r31,STK_REG(r31)(r1)
693
694 /* Step 1:
695 *
696 * Check permissions, atomically mark the linux PTE busy
697 * and hashed.
698 */
6991:
700 ldarx r31,0,r6
701 /* Check access rights (access & ~(pte_val(*ptep))) */
702 andc. r0,r4,r31
703 bne- ht64_wrong_access
704 /* Check if PTE is busy */
705 andi. r0,r31,_PAGE_BUSY
706 /* If so, just bail out and refault if needed. Someone else
707 * is changing this PTE anyway and might hash it.
708 */
709 bne- ht64_bail_ok
Paul Mackerrasbf72aeb2006-06-15 10:45:18 +1000710BEGIN_FTR_SECTION
711 /* Check if PTE has the cache-inhibit bit set */
712 andi. r0,r31,_PAGE_NO_CACHE
713 /* If so, bail out and refault as a 4k page */
714 bne- ht64_bail_ok
715END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100716 /* Prepare new PTE value (turn access RW into DIRTY, then
717 * add BUSY,HASHPTE and ACCESSED)
718 */
719 rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
720 or r30,r30,r31
721 ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
722 /* Write the linux PTE atomically (setting busy) */
723 stdcx. r30,0,r6
724 bne- 1b
725 isync
726
727 /* Step 2:
728 *
729 * Insert/Update the HPTE in the hash table. At this point,
730 * r4 (access) is re-useable, we use it for the new HPTE flags
731 */
732
Paul Mackerras1189be62007-10-11 20:37:10 +1000733BEGIN_FTR_SECTION
734 cmpdi r9,0 /* check segment size */
735 bne 3f
736END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100737 /* Calc va and put it in r29 */
738 rldicr r29,r5,28,63-28
739 rldicl r3,r3,0,36
740 or r29,r3,r29
741
742 /* Calculate hash value for primary slot and store it in r28 */
743 rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */
744 rldicl r0,r3,64-16,52 /* (ea >> 16) & 0xfff */
745 xor r28,r5,r0
Paul Mackerras1189be62007-10-11 20:37:10 +1000746 b 4f
747
7483: /* Calc VA and hash in r29 and r28 for 1T segment */
749 sldi r29,r5,40 /* vsid << 40 */
750 clrldi r3,r3,24 /* ea & 0xffffffffff */
751 rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */
752 clrldi r5,r5,40 /* vsid & 0xffffff */
753 rldicl r0,r3,64-16,40 /* (ea >> 16) & 0xffffff */
754 xor r28,r28,r5
755 or r29,r3,r29 /* VA */
756 xor r28,r28,r0 /* hash */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100757
758 /* Convert linux PTE bits into HW equivalents */
Paul Mackerras1189be62007-10-11 20:37:10 +10007594: andi. r3,r30,0x1fe /* Get basic set of flags */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100760 xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */
761 rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
762 rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */
763 and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
764 andc r0,r30,r0 /* r0 = pte & ~r0 */
765 rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
Benjamin Herrenschmidtc5cf0e32006-05-30 14:14:19 +1000766 ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100767
768 /* We eventually do the icache sync here (maybe inline that
769 * code rather than call a C function...)
770 */
771BEGIN_FTR_SECTION
772 mr r4,r30
773 mr r5,r7
774 bl .hash_page_do_lazy_icache
775END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
776
777 /* At this point, r3 contains new PP bits, save them in
778 * place of "access" in the param area (sic)
779 */
780 std r3,STK_PARM(r4)(r1)
781
782 /* Get htab_hash_mask */
783 ld r4,htab_hash_mask@got(2)
784 ld r27,0(r4) /* htab_hash_mask -> r27 */
785
786 /* Check if we may already be in the hashtable, in this case, we
787 * go to out-of-line code to try to modify the HPTE
788 */
789 andi. r0,r31,_PAGE_HASHPTE
790 bne ht64_modify_pte
791
792ht64_insert_pte:
793 /* Clear hpte bits in new pte (we also clear BUSY btw) and
794 * add _PAGE_HASHPTE
795 */
796 lis r0,_PAGE_HPTEFLAGS@h
797 ori r0,r0,_PAGE_HPTEFLAGS@l
798 andc r30,r30,r0
799 ori r30,r30,_PAGE_HASHPTE
800
801 /* Phyical address in r5 */
802 rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
803 sldi r5,r5,PAGE_SHIFT
804
805 /* Calculate primary group hash */
806 and r0,r28,r27
807 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
808
809 /* Call ppc_md.hpte_insert */
810 ld r6,STK_PARM(r4)(r1) /* Retreive new pp bits */
811 mr r4,r29 /* Retreive va */
812 li r7,0 /* !bolted, !secondary */
813 li r8,MMU_PAGE_64K
Paul Mackerras1189be62007-10-11 20:37:10 +1000814 ld r9,STK_PARM(r9)(r1) /* segment size */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100815_GLOBAL(ht64_call_hpte_insert1)
816 bl . /* patched by htab_finish_init() */
817 cmpdi 0,r3,0
818 bge ht64_pte_insert_ok /* Insertion successful */
819 cmpdi 0,r3,-2 /* Critical failure */
820 beq- ht64_pte_insert_failure
821
822 /* Now try secondary slot */
823
824 /* Phyical address in r5 */
825 rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
826 sldi r5,r5,PAGE_SHIFT
827
828 /* Calculate secondary group hash */
829 andc r0,r27,r28
830 rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */
831
832 /* Call ppc_md.hpte_insert */
833 ld r6,STK_PARM(r4)(r1) /* Retreive new pp bits */
834 mr r4,r29 /* Retreive va */
835 li r7,HPTE_V_SECONDARY /* !bolted, secondary */
836 li r8,MMU_PAGE_64K
Paul Mackerras1189be62007-10-11 20:37:10 +1000837 ld r9,STK_PARM(r9)(r1) /* segment size */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100838_GLOBAL(ht64_call_hpte_insert2)
839 bl . /* patched by htab_finish_init() */
840 cmpdi 0,r3,0
841 bge+ ht64_pte_insert_ok /* Insertion successful */
842 cmpdi 0,r3,-2 /* Critical failure */
843 beq- ht64_pte_insert_failure
844
845 /* Both are full, we need to evict something */
846 mftb r0
847 /* Pick a random group based on TB */
848 andi. r0,r0,1
849 mr r5,r28
850 bne 2f
851 not r5,r5
8522: and r0,r5,r27
853 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
854 /* Call ppc_md.hpte_remove */
855_GLOBAL(ht64_call_hpte_remove)
856 bl . /* patched by htab_finish_init() */
857
858 /* Try all again */
859 b ht64_insert_pte
860
861ht64_bail_ok:
862 li r3,0
863 b ht64_bail
864
865ht64_pte_insert_ok:
866 /* Insert slot number & secondary bit in PTE */
867 rldimi r30,r3,12,63-15
868
869 /* Write out the PTE with a normal write
870 * (maybe add eieio may be good still ?)
871 */
872ht64_write_out_pte:
873 ld r6,STK_PARM(r6)(r1)
874 std r30,0(r6)
875 li r3, 0
876ht64_bail:
877 ld r27,STK_REG(r27)(r1)
878 ld r28,STK_REG(r28)(r1)
879 ld r29,STK_REG(r29)(r1)
880 ld r30,STK_REG(r30)(r1)
881 ld r31,STK_REG(r31)(r1)
882 addi r1,r1,STACKFRAMESIZE
883 ld r0,16(r1)
884 mtlr r0
885 blr
886
887ht64_modify_pte:
888 /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
889 mr r4,r3
890 rlwinm r3,r31,32-12,29,31
891
892 /* Secondary group ? if yes, get a inverted hash value */
893 mr r5,r28
894 andi. r0,r31,_PAGE_F_SECOND
895 beq 1f
896 not r5,r5
8971:
898 /* Calculate proper slot value for ppc_md.hpte_updatepp */
899 and r0,r5,r27
900 rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */
901 add r3,r0,r3 /* add slot idx */
902
903 /* Call ppc_md.hpte_updatepp */
904 mr r5,r29 /* va */
905 li r6,MMU_PAGE_64K
Paul Mackerras1189be62007-10-11 20:37:10 +1000906 ld r7,STK_PARM(r9)(r1) /* segment size */
907 ld r8,STK_PARM(r8)(r1) /* get "local" param */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100908_GLOBAL(ht64_call_hpte_updatepp)
909 bl . /* patched by htab_finish_init() */
910
911 /* if we failed because typically the HPTE wasn't really here
912 * we try an insertion.
913 */
914 cmpdi 0,r3,-1
915 beq- ht64_insert_pte
916
917 /* Clear the BUSY bit and Write out the PTE */
918 li r0,_PAGE_BUSY
919 andc r30,r30,r0
920 b ht64_write_out_pte
921
922ht64_wrong_access:
923 /* Bail out clearing reservation */
924 stdcx. r31,0,r6
925 li r3,1
926 b ht64_bail
927
928ht64_pte_insert_failure:
929 /* Bail out restoring old PTE */
930 ld r6,STK_PARM(r6)(r1)
931 std r31,0(r6)
932 li r3,-1
933 b ht64_bail
934
935
Benjamin Herrenschmidt16c2d472007-05-08 16:27:28 +1000936#endif /* CONFIG_PPC_HAS_HASH_64K */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100937
938
939/*****************************************************************************
940 * *
941 * Huge pages implementation is in hugetlbpage.c *
942 * *
943 *****************************************************************************/