/*1* ppc64 MMU hashtable management routines2*3* (c) Copyright IBM Corp. 2003, 20054*5* Maintained by: Benjamin Herrenschmidt6* <[email protected]>7*8* This file is covered by the GNU Public Licence v2 as9* described in the kernel's COPYING file.10*/1112#include <asm/reg.h>13#include <asm/pgtable.h>14#include <asm/mmu.h>15#include <asm/page.h>16#include <asm/types.h>17#include <asm/ppc_asm.h>18#include <asm/asm-offsets.h>19#include <asm/cputable.h>2021.text2223/*24* Stackframe:25*26* +-> Back chain (SP + 256)27* | General register save area (SP + 112)28* | Parameter save area (SP + 48)29* | TOC save area (SP + 40)30* | link editor doubleword (SP + 32)31* | compiler doubleword (SP + 24)32* | LR save area (SP + 16)33* | CR save area (SP + 8)34* SP ---> +-- Back chain (SP + 0)35*/36#define STACKFRAMESIZE 2563738/* Save parameters offsets */39#define STK_PARM(i) (STACKFRAMESIZE + 48 + ((i)-3)*8)4041/* Save non-volatile offsets */42#define STK_REG(i) (112 + ((i)-14)*8)434445#ifndef CONFIG_PPC_64K_PAGES4647/*****************************************************************************48* *49* 4K SW & 4K HW pages implementation *50* *51*****************************************************************************/525354/*55* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,56* pte_t *ptep, unsigned long trap, int local, int ssize)57*58* Adds a 4K page to the hash table in a segment of 4K pages only59*/6061_GLOBAL(__hash_page_4K)62mflr r063std r0,16(r1)64stdu r1,-STACKFRAMESIZE(r1)65/* Save all params that we need after a function call */66std r6,STK_PARM(r6)(r1)67std r8,STK_PARM(r8)(r1)68std r9,STK_PARM(r9)(r1)6970/* Save non-volatile registers.71* r31 will hold "old PTE"72* r30 is "new PTE"73* r29 is "va"74* r28 is a hash value75* r27 is hashtab mask (maybe dynamic patched instead ?)76*/77std r27,STK_REG(r27)(r1)78std r28,STK_REG(r28)(r1)79std r29,STK_REG(r29)(r1)80std r30,STK_REG(r30)(r1)81std r31,STK_REG(r31)(r1)8283/* Step 1:84*85* Check permissions, atomically mark the linux PTE busy86* and hashed.87*/881:89ldarx r31,0,r690/* Check access rights (access & ~(pte_val(*ptep))) */91andc. r0,r4,r3192bne- htab_wrong_access93/* Check if PTE is busy */94andi. r0,r31,_PAGE_BUSY95/* If so, just bail out and refault if needed. Someone else96* is changing this PTE anyway and might hash it.97*/98bne- htab_bail_ok99100/* Prepare new PTE value (turn access RW into DIRTY, then101* add BUSY,HASHPTE and ACCESSED)102*/103rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */104or r30,r30,r31105ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE106/* Write the linux PTE atomically (setting busy) */107stdcx. r30,0,r6108bne- 1b109isync110111/* Step 2:112*113* Insert/Update the HPTE in the hash table. At this point,114* r4 (access) is re-useable, we use it for the new HPTE flags115*/116117BEGIN_FTR_SECTION118cmpdi r9,0 /* check segment size */119bne 3f120END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)121/* Calc va and put it in r29 */122rldicr r29,r5,28,63-28123rldicl r3,r3,0,36124or r29,r3,r29125126/* Calculate hash value for primary slot and store it in r28 */127rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */128rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */129xor r28,r5,r0130b 4f1311323: /* Calc VA and hash in r29 and r28 for 1T segment */133sldi r29,r5,40 /* vsid << 40 */134clrldi r3,r3,24 /* ea & 0xffffffffff */135rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */136clrldi r5,r5,40 /* vsid & 0xffffff */137rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */138xor r28,r28,r5139or r29,r3,r29 /* VA */140xor r28,r28,r0 /* hash */141142/* Convert linux PTE bits into HW equivalents */1434: andi. r3,r30,0x1fe /* Get basic set of flags */144xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */145rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */146rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */147and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/148andc r0,r30,r0 /* r0 = pte & ~r0 */149rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */150ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */151152/* We eventually do the icache sync here (maybe inline that153* code rather than call a C function...)154*/155BEGIN_FTR_SECTION156mr r4,r30157mr r5,r7158bl .hash_page_do_lazy_icache159END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)160161/* At this point, r3 contains new PP bits, save them in162* place of "access" in the param area (sic)163*/164std r3,STK_PARM(r4)(r1)165166/* Get htab_hash_mask */167ld r4,htab_hash_mask@got(2)168ld r27,0(r4) /* htab_hash_mask -> r27 */169170/* Check if we may already be in the hashtable, in this case, we171* go to out-of-line code to try to modify the HPTE172*/173andi. r0,r31,_PAGE_HASHPTE174bne htab_modify_pte175176htab_insert_pte:177/* Clear hpte bits in new pte (we also clear BUSY btw) and178* add _PAGE_HASHPTE179*/180lis r0,_PAGE_HPTEFLAGS@h181ori r0,r0,_PAGE_HPTEFLAGS@l182andc r30,r30,r0183ori r30,r30,_PAGE_HASHPTE184185/* physical address r5 */186rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT187sldi r5,r5,PAGE_SHIFT188189/* Calculate primary group hash */190and r0,r28,r27191rldicr r3,r0,3,63-3 /* r3 = (hash & mask) << 3 */192193/* Call ppc_md.hpte_insert */194ld r6,STK_PARM(r4)(r1) /* Retrieve new pp bits */195mr r4,r29 /* Retrieve va */196li r7,0 /* !bolted, !secondary */197li r8,MMU_PAGE_4K /* page size */198ld r9,STK_PARM(r9)(r1) /* segment size */199_GLOBAL(htab_call_hpte_insert1)200bl . /* Patched by htab_finish_init() */201cmpdi 0,r3,0202bge htab_pte_insert_ok /* Insertion successful */203cmpdi 0,r3,-2 /* Critical failure */204beq- htab_pte_insert_failure205206/* Now try secondary slot */207208/* physical address r5 */209rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT210sldi r5,r5,PAGE_SHIFT211212/* Calculate secondary group hash */213andc r0,r27,r28214rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */215216/* Call ppc_md.hpte_insert */217ld r6,STK_PARM(r4)(r1) /* Retrieve new pp bits */218mr r4,r29 /* Retrieve va */219li r7,HPTE_V_SECONDARY /* !bolted, secondary */220li r8,MMU_PAGE_4K /* page size */221ld r9,STK_PARM(r9)(r1) /* segment size */222_GLOBAL(htab_call_hpte_insert2)223bl . /* Patched by htab_finish_init() */224cmpdi 0,r3,0225bge+ htab_pte_insert_ok /* Insertion successful */226cmpdi 0,r3,-2 /* Critical failure */227beq- htab_pte_insert_failure228229/* Both are full, we need to evict something */230mftb r0231/* Pick a random group based on TB */232andi. r0,r0,1233mr r5,r28234bne 2f235not r5,r52362: and r0,r5,r27237rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */238/* Call ppc_md.hpte_remove */239_GLOBAL(htab_call_hpte_remove)240bl . /* Patched by htab_finish_init() */241242/* Try all again */243b htab_insert_pte244245htab_bail_ok:246li r3,0247b htab_bail248249htab_pte_insert_ok:250/* Insert slot number & secondary bit in PTE */251rldimi r30,r3,12,63-15252253/* Write out the PTE with a normal write254* (maybe add eieio may be good still ?)255*/256htab_write_out_pte:257ld r6,STK_PARM(r6)(r1)258std r30,0(r6)259li r3, 0260htab_bail:261ld r27,STK_REG(r27)(r1)262ld r28,STK_REG(r28)(r1)263ld r29,STK_REG(r29)(r1)264ld r30,STK_REG(r30)(r1)265ld r31,STK_REG(r31)(r1)266addi r1,r1,STACKFRAMESIZE267ld r0,16(r1)268mtlr r0269blr270271htab_modify_pte:272/* Keep PP bits in r4 and slot idx from the PTE around in r3 */273mr r4,r3274rlwinm r3,r31,32-12,29,31275276/* Secondary group ? if yes, get a inverted hash value */277mr r5,r28278andi. r0,r31,_PAGE_SECONDARY279beq 1f280not r5,r52811:282/* Calculate proper slot value for ppc_md.hpte_updatepp */283and r0,r5,r27284rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */285add r3,r0,r3 /* add slot idx */286287/* Call ppc_md.hpte_updatepp */288mr r5,r29 /* va */289li r6,MMU_PAGE_4K /* page size */290ld r7,STK_PARM(r9)(r1) /* segment size */291ld r8,STK_PARM(r8)(r1) /* get "local" param */292_GLOBAL(htab_call_hpte_updatepp)293bl . /* Patched by htab_finish_init() */294295/* if we failed because typically the HPTE wasn't really here296* we try an insertion.297*/298cmpdi 0,r3,-1299beq- htab_insert_pte300301/* Clear the BUSY bit and Write out the PTE */302li r0,_PAGE_BUSY303andc r30,r30,r0304b htab_write_out_pte305306htab_wrong_access:307/* Bail out clearing reservation */308stdcx. r31,0,r6309li r3,1310b htab_bail311312htab_pte_insert_failure:313/* Bail out restoring old PTE */314ld r6,STK_PARM(r6)(r1)315std r31,0(r6)316li r3,-1317b htab_bail318319320#else /* CONFIG_PPC_64K_PAGES */321322323/*****************************************************************************324* *325* 64K SW & 4K or 64K HW in a 4K segment pages implementation *326* *327*****************************************************************************/328329/* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,330* pte_t *ptep, unsigned long trap, int local, int ssize,331* int subpg_prot)332*/333334/*335* For now, we do NOT implement Admixed pages336*/337_GLOBAL(__hash_page_4K)338mflr r0339std r0,16(r1)340stdu r1,-STACKFRAMESIZE(r1)341/* Save all params that we need after a function call */342std r6,STK_PARM(r6)(r1)343std r8,STK_PARM(r8)(r1)344std r9,STK_PARM(r9)(r1)345346/* Save non-volatile registers.347* r31 will hold "old PTE"348* r30 is "new PTE"349* r29 is "va"350* r28 is a hash value351* r27 is hashtab mask (maybe dynamic patched instead ?)352* r26 is the hidx mask353* r25 is the index in combo page354*/355std r25,STK_REG(r25)(r1)356std r26,STK_REG(r26)(r1)357std r27,STK_REG(r27)(r1)358std r28,STK_REG(r28)(r1)359std r29,STK_REG(r29)(r1)360std r30,STK_REG(r30)(r1)361std r31,STK_REG(r31)(r1)362363/* Step 1:364*365* Check permissions, atomically mark the linux PTE busy366* and hashed.367*/3681:369ldarx r31,0,r6370/* Check access rights (access & ~(pte_val(*ptep))) */371andc. r0,r4,r31372bne- htab_wrong_access373/* Check if PTE is busy */374andi. r0,r31,_PAGE_BUSY375/* If so, just bail out and refault if needed. Someone else376* is changing this PTE anyway and might hash it.377*/378bne- htab_bail_ok379/* Prepare new PTE value (turn access RW into DIRTY, then380* add BUSY and ACCESSED)381*/382rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */383or r30,r30,r31384ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED385oris r30,r30,_PAGE_COMBO@h386/* Write the linux PTE atomically (setting busy) */387stdcx. r30,0,r6388bne- 1b389isync390391/* Step 2:392*393* Insert/Update the HPTE in the hash table. At this point,394* r4 (access) is re-useable, we use it for the new HPTE flags395*/396397/* Load the hidx index */398rldicl r25,r3,64-12,60399400BEGIN_FTR_SECTION401cmpdi r9,0 /* check segment size */402bne 3f403END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)404/* Calc va and put it in r29 */405rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */406rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */407or r29,r3,r29 /* r29 = va */408409/* Calculate hash value for primary slot and store it in r28 */410rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */411rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */412xor r28,r5,r0413b 4f4144153: /* Calc VA and hash in r29 and r28 for 1T segment */416sldi r29,r5,40 /* vsid << 40 */417clrldi r3,r3,24 /* ea & 0xffffffffff */418rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */419clrldi r5,r5,40 /* vsid & 0xffffff */420rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */421xor r28,r28,r5422or r29,r3,r29 /* VA */423xor r28,r28,r0 /* hash */424425/* Convert linux PTE bits into HW equivalents */4264:427#ifdef CONFIG_PPC_SUBPAGE_PROT428andc r10,r30,r10429andi. r3,r10,0x1fe /* Get basic set of flags */430rlwinm r0,r10,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */431#else432andi. r3,r30,0x1fe /* Get basic set of flags */433rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */434#endif435xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */436rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */437and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/438andc r0,r3,r0 /* r0 = pte & ~r0 */439rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */440ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */441442/* We eventually do the icache sync here (maybe inline that443* code rather than call a C function...)444*/445BEGIN_FTR_SECTION446mr r4,r30447mr r5,r7448bl .hash_page_do_lazy_icache449END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)450451/* At this point, r3 contains new PP bits, save them in452* place of "access" in the param area (sic)453*/454std r3,STK_PARM(r4)(r1)455456/* Get htab_hash_mask */457ld r4,htab_hash_mask@got(2)458ld r27,0(r4) /* htab_hash_mask -> r27 */459460/* Check if we may already be in the hashtable, in this case, we461* go to out-of-line code to try to modify the HPTE. We look for462* the bit at (1 >> (index + 32))463*/464rldicl. r0,r31,64-12,48465li r26,0 /* Default hidx */466beq htab_insert_pte467468/*469* Check if the pte was already inserted into the hash table470* as a 64k HW page, and invalidate the 64k HPTE if so.471*/472andis. r0,r31,_PAGE_COMBO@h473beq htab_inval_old_hpte474475ld r6,STK_PARM(r6)(r1)476ori r26,r6,0x8000 /* Load the hidx mask */477ld r26,0(r26)478addi r5,r25,36 /* Check actual HPTE_SUB bit, this */479rldcr. r0,r31,r5,0 /* must match pgtable.h definition */480bne htab_modify_pte481482htab_insert_pte:483/* real page number in r5, PTE RPN value + index */484andis. r0,r31,_PAGE_4K_PFN@h485srdi r5,r31,PTE_RPN_SHIFT486bne- htab_special_pfn487sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT488add r5,r5,r25489htab_special_pfn:490sldi r5,r5,HW_PAGE_SHIFT491492/* Calculate primary group hash */493and r0,r28,r27494rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */495496/* Call ppc_md.hpte_insert */497ld r6,STK_PARM(r4)(r1) /* Retrieve new pp bits */498mr r4,r29 /* Retrieve va */499li r7,0 /* !bolted, !secondary */500li r8,MMU_PAGE_4K /* page size */501ld r9,STK_PARM(r9)(r1) /* segment size */502_GLOBAL(htab_call_hpte_insert1)503bl . /* patched by htab_finish_init() */504cmpdi 0,r3,0505bge htab_pte_insert_ok /* Insertion successful */506cmpdi 0,r3,-2 /* Critical failure */507beq- htab_pte_insert_failure508509/* Now try secondary slot */510511/* real page number in r5, PTE RPN value + index */512andis. r0,r31,_PAGE_4K_PFN@h513srdi r5,r31,PTE_RPN_SHIFT514bne- 3f515sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT516add r5,r5,r255173: sldi r5,r5,HW_PAGE_SHIFT518519/* Calculate secondary group hash */520andc r0,r27,r28521rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */522523/* Call ppc_md.hpte_insert */524ld r6,STK_PARM(r4)(r1) /* Retrieve new pp bits */525mr r4,r29 /* Retrieve va */526li r7,HPTE_V_SECONDARY /* !bolted, secondary */527li r8,MMU_PAGE_4K /* page size */528ld r9,STK_PARM(r9)(r1) /* segment size */529_GLOBAL(htab_call_hpte_insert2)530bl . /* patched by htab_finish_init() */531cmpdi 0,r3,0532bge+ htab_pte_insert_ok /* Insertion successful */533cmpdi 0,r3,-2 /* Critical failure */534beq- htab_pte_insert_failure535536/* Both are full, we need to evict something */537mftb r0538/* Pick a random group based on TB */539andi. r0,r0,1540mr r5,r28541bne 2f542not r5,r55432: and r0,r5,r27544rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */545/* Call ppc_md.hpte_remove */546_GLOBAL(htab_call_hpte_remove)547bl . /* patched by htab_finish_init() */548549/* Try all again */550b htab_insert_pte551552/*553* Call out to C code to invalidate an 64k HW HPTE that is554* useless now that the segment has been switched to 4k pages.555*/556htab_inval_old_hpte:557mr r3,r29 /* virtual addr */558mr r4,r31 /* PTE.pte */559li r5,0 /* PTE.hidx */560li r6,MMU_PAGE_64K /* psize */561ld r7,STK_PARM(r9)(r1) /* ssize */562ld r8,STK_PARM(r8)(r1) /* local */563bl .flush_hash_page564/* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */565lis r0,_PAGE_HPTE_SUB@h566ori r0,r0,_PAGE_HPTE_SUB@l567andc r30,r30,r0568b htab_insert_pte569570htab_bail_ok:571li r3,0572b htab_bail573574htab_pte_insert_ok:575/* Insert slot number & secondary bit in PTE second half,576* clear _PAGE_BUSY and set approriate HPTE slot bit577*/578ld r6,STK_PARM(r6)(r1)579li r0,_PAGE_BUSY580andc r30,r30,r0581/* HPTE SUB bit */582li r0,1583subfic r5,r25,27 /* Must match bit position in */584sld r0,r0,r5 /* pgtable.h */585or r30,r30,r0586/* hindx */587sldi r5,r25,2588sld r3,r3,r5589li r4,0xf590sld r4,r4,r5591andc r26,r26,r4592or r26,r26,r3593ori r5,r6,0x8000594std r26,0(r5)595lwsync596std r30,0(r6)597li r3, 0598htab_bail:599ld r25,STK_REG(r25)(r1)600ld r26,STK_REG(r26)(r1)601ld r27,STK_REG(r27)(r1)602ld r28,STK_REG(r28)(r1)603ld r29,STK_REG(r29)(r1)604ld r30,STK_REG(r30)(r1)605ld r31,STK_REG(r31)(r1)606addi r1,r1,STACKFRAMESIZE607ld r0,16(r1)608mtlr r0609blr610611htab_modify_pte:612/* Keep PP bits in r4 and slot idx from the PTE around in r3 */613mr r4,r3614sldi r5,r25,2615srd r3,r26,r5616617/* Secondary group ? if yes, get a inverted hash value */618mr r5,r28619andi. r0,r3,0x8 /* page secondary ? */620beq 1f621not r5,r56221: andi. r3,r3,0x7 /* extract idx alone */623624/* Calculate proper slot value for ppc_md.hpte_updatepp */625and r0,r5,r27626rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */627add r3,r0,r3 /* add slot idx */628629/* Call ppc_md.hpte_updatepp */630mr r5,r29 /* va */631li r6,MMU_PAGE_4K /* page size */632ld r7,STK_PARM(r9)(r1) /* segment size */633ld r8,STK_PARM(r8)(r1) /* get "local" param */634_GLOBAL(htab_call_hpte_updatepp)635bl . /* patched by htab_finish_init() */636637/* if we failed because typically the HPTE wasn't really here638* we try an insertion.639*/640cmpdi 0,r3,-1641beq- htab_insert_pte642643/* Clear the BUSY bit and Write out the PTE */644li r0,_PAGE_BUSY645andc r30,r30,r0646ld r6,STK_PARM(r6)(r1)647std r30,0(r6)648li r3,0649b htab_bail650651htab_wrong_access:652/* Bail out clearing reservation */653stdcx. r31,0,r6654li r3,1655b htab_bail656657htab_pte_insert_failure:658/* Bail out restoring old PTE */659ld r6,STK_PARM(r6)(r1)660std r31,0(r6)661li r3,-1662b htab_bail663664#endif /* CONFIG_PPC_64K_PAGES */665666#ifdef CONFIG_PPC_HAS_HASH_64K667668/*****************************************************************************669* *670* 64K SW & 64K HW in a 64K segment pages implementation *671* *672*****************************************************************************/673674_GLOBAL(__hash_page_64K)675mflr r0676std r0,16(r1)677stdu r1,-STACKFRAMESIZE(r1)678/* Save all params that we need after a function call */679std r6,STK_PARM(r6)(r1)680std r8,STK_PARM(r8)(r1)681std r9,STK_PARM(r9)(r1)682683/* Save non-volatile registers.684* r31 will hold "old PTE"685* r30 is "new PTE"686* r29 is "va"687* r28 is a hash value688* r27 is hashtab mask (maybe dynamic patched instead ?)689*/690std r27,STK_REG(r27)(r1)691std r28,STK_REG(r28)(r1)692std r29,STK_REG(r29)(r1)693std r30,STK_REG(r30)(r1)694std r31,STK_REG(r31)(r1)695696/* Step 1:697*698* Check permissions, atomically mark the linux PTE busy699* and hashed.700*/7011:702ldarx r31,0,r6703/* Check access rights (access & ~(pte_val(*ptep))) */704andc. r0,r4,r31705bne- ht64_wrong_access706/* Check if PTE is busy */707andi. r0,r31,_PAGE_BUSY708/* If so, just bail out and refault if needed. Someone else709* is changing this PTE anyway and might hash it.710*/711bne- ht64_bail_ok712BEGIN_FTR_SECTION713/* Check if PTE has the cache-inhibit bit set */714andi. r0,r31,_PAGE_NO_CACHE715/* If so, bail out and refault as a 4k page */716bne- ht64_bail_ok717END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)718/* Prepare new PTE value (turn access RW into DIRTY, then719* add BUSY and ACCESSED)720*/721rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */722or r30,r30,r31723ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED724/* Write the linux PTE atomically (setting busy) */725stdcx. r30,0,r6726bne- 1b727isync728729/* Step 2:730*731* Insert/Update the HPTE in the hash table. At this point,732* r4 (access) is re-useable, we use it for the new HPTE flags733*/734735BEGIN_FTR_SECTION736cmpdi r9,0 /* check segment size */737bne 3f738END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)739/* Calc va and put it in r29 */740rldicr r29,r5,28,63-28741rldicl r3,r3,0,36742or r29,r3,r29743744/* Calculate hash value for primary slot and store it in r28 */745rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */746rldicl r0,r3,64-16,52 /* (ea >> 16) & 0xfff */747xor r28,r5,r0748b 4f7497503: /* Calc VA and hash in r29 and r28 for 1T segment */751sldi r29,r5,40 /* vsid << 40 */752clrldi r3,r3,24 /* ea & 0xffffffffff */753rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */754clrldi r5,r5,40 /* vsid & 0xffffff */755rldicl r0,r3,64-16,40 /* (ea >> 16) & 0xffffff */756xor r28,r28,r5757or r29,r3,r29 /* VA */758xor r28,r28,r0 /* hash */759760/* Convert linux PTE bits into HW equivalents */7614: andi. r3,r30,0x1fe /* Get basic set of flags */762xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */763rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */764rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */765and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/766andc r0,r30,r0 /* r0 = pte & ~r0 */767rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */768ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */769770/* We eventually do the icache sync here (maybe inline that771* code rather than call a C function...)772*/773BEGIN_FTR_SECTION774mr r4,r30775mr r5,r7776bl .hash_page_do_lazy_icache777END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)778779/* At this point, r3 contains new PP bits, save them in780* place of "access" in the param area (sic)781*/782std r3,STK_PARM(r4)(r1)783784/* Get htab_hash_mask */785ld r4,htab_hash_mask@got(2)786ld r27,0(r4) /* htab_hash_mask -> r27 */787788/* Check if we may already be in the hashtable, in this case, we789* go to out-of-line code to try to modify the HPTE790*/791rldicl. r0,r31,64-12,48792bne ht64_modify_pte793794ht64_insert_pte:795/* Clear hpte bits in new pte (we also clear BUSY btw) and796* add _PAGE_HPTE_SUB0797*/798lis r0,_PAGE_HPTEFLAGS@h799ori r0,r0,_PAGE_HPTEFLAGS@l800andc r30,r30,r0801#ifdef CONFIG_PPC_64K_PAGES802oris r30,r30,_PAGE_HPTE_SUB0@h803#else804ori r30,r30,_PAGE_HASHPTE805#endif806/* Phyical address in r5 */807rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT808sldi r5,r5,PAGE_SHIFT809810/* Calculate primary group hash */811and r0,r28,r27812rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */813814/* Call ppc_md.hpte_insert */815ld r6,STK_PARM(r4)(r1) /* Retrieve new pp bits */816mr r4,r29 /* Retrieve va */817li r7,0 /* !bolted, !secondary */818li r8,MMU_PAGE_64K819ld r9,STK_PARM(r9)(r1) /* segment size */820_GLOBAL(ht64_call_hpte_insert1)821bl . /* patched by htab_finish_init() */822cmpdi 0,r3,0823bge ht64_pte_insert_ok /* Insertion successful */824cmpdi 0,r3,-2 /* Critical failure */825beq- ht64_pte_insert_failure826827/* Now try secondary slot */828829/* Phyical address in r5 */830rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT831sldi r5,r5,PAGE_SHIFT832833/* Calculate secondary group hash */834andc r0,r27,r28835rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */836837/* Call ppc_md.hpte_insert */838ld r6,STK_PARM(r4)(r1) /* Retrieve new pp bits */839mr r4,r29 /* Retrieve va */840li r7,HPTE_V_SECONDARY /* !bolted, secondary */841li r8,MMU_PAGE_64K842ld r9,STK_PARM(r9)(r1) /* segment size */843_GLOBAL(ht64_call_hpte_insert2)844bl . /* patched by htab_finish_init() */845cmpdi 0,r3,0846bge+ ht64_pte_insert_ok /* Insertion successful */847cmpdi 0,r3,-2 /* Critical failure */848beq- ht64_pte_insert_failure849850/* Both are full, we need to evict something */851mftb r0852/* Pick a random group based on TB */853andi. r0,r0,1854mr r5,r28855bne 2f856not r5,r58572: and r0,r5,r27858rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */859/* Call ppc_md.hpte_remove */860_GLOBAL(ht64_call_hpte_remove)861bl . /* patched by htab_finish_init() */862863/* Try all again */864b ht64_insert_pte865866ht64_bail_ok:867li r3,0868b ht64_bail869870ht64_pte_insert_ok:871/* Insert slot number & secondary bit in PTE */872rldimi r30,r3,12,63-15873874/* Write out the PTE with a normal write875* (maybe add eieio may be good still ?)876*/877ht64_write_out_pte:878ld r6,STK_PARM(r6)(r1)879std r30,0(r6)880li r3, 0881ht64_bail:882ld r27,STK_REG(r27)(r1)883ld r28,STK_REG(r28)(r1)884ld r29,STK_REG(r29)(r1)885ld r30,STK_REG(r30)(r1)886ld r31,STK_REG(r31)(r1)887addi r1,r1,STACKFRAMESIZE888ld r0,16(r1)889mtlr r0890blr891892ht64_modify_pte:893/* Keep PP bits in r4 and slot idx from the PTE around in r3 */894mr r4,r3895rlwinm r3,r31,32-12,29,31896897/* Secondary group ? if yes, get a inverted hash value */898mr r5,r28899andi. r0,r31,_PAGE_F_SECOND900beq 1f901not r5,r59021:903/* Calculate proper slot value for ppc_md.hpte_updatepp */904and r0,r5,r27905rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */906add r3,r0,r3 /* add slot idx */907908/* Call ppc_md.hpte_updatepp */909mr r5,r29 /* va */910li r6,MMU_PAGE_64K911ld r7,STK_PARM(r9)(r1) /* segment size */912ld r8,STK_PARM(r8)(r1) /* get "local" param */913_GLOBAL(ht64_call_hpte_updatepp)914bl . /* patched by htab_finish_init() */915916/* if we failed because typically the HPTE wasn't really here917* we try an insertion.918*/919cmpdi 0,r3,-1920beq- ht64_insert_pte921922/* Clear the BUSY bit and Write out the PTE */923li r0,_PAGE_BUSY924andc r30,r30,r0925b ht64_write_out_pte926927ht64_wrong_access:928/* Bail out clearing reservation */929stdcx. r31,0,r6930li r3,1931b ht64_bail932933ht64_pte_insert_failure:934/* Bail out restoring old PTE */935ld r6,STK_PARM(r6)(r1)936std r31,0(r6)937li r3,-1938b ht64_bail939940941#endif /* CONFIG_PPC_HAS_HASH_64K */942943944/*****************************************************************************945* *946* Huge pages implementation is in hugetlbpage.c *947* *948*****************************************************************************/949950951