The ASM version of hash computation function was truncating the upper bit. Make the ASM version similar to hpt_hash function. Remove masking vsid bits. Without this patch, we observed hang during bootup due to not satisfying page fault request correctly. The fault handler used wrong hash values to update the HPTE. Hence we kept looping with page fault. hash_page(ea=000001003e260008, access=203, trap=300 ip=3fff91787134 dsisr 42000000 The computed value of hash 000000000f22f390 update: avpnv=4003e46054003e00, hash=000000000722f390, f=80000006, psize: 2 ... BenH: The over-masking has been there for ever but only hurts with the new 64T support introduced in 3.7 Reported-by: Mike Qiu <qiudayu@linux.vnet.ibm.com> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Tested-by: Mike Qiu <qiudayu@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> CC: <stable@vger.kernel.org> [v3.7]
		
			
				
	
	
		
			972 lines
		
	
	
	
		
			26 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			972 lines
		
	
	
	
		
			26 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 * ppc64 MMU hashtable management routines
 | 
						|
 *
 | 
						|
 * (c) Copyright IBM Corp. 2003, 2005
 | 
						|
 *
 | 
						|
 * Maintained by: Benjamin Herrenschmidt
 | 
						|
 *                <benh@kernel.crashing.org>
 | 
						|
 *
 | 
						|
 * This file is covered by the GNU Public Licence v2 as
 | 
						|
 * described in the kernel's COPYING file.
 | 
						|
 */
 | 
						|
 | 
						|
#include <asm/reg.h>
 | 
						|
#include <asm/pgtable.h>
 | 
						|
#include <asm/mmu.h>
 | 
						|
#include <asm/page.h>
 | 
						|
#include <asm/types.h>
 | 
						|
#include <asm/ppc_asm.h>
 | 
						|
#include <asm/asm-offsets.h>
 | 
						|
#include <asm/cputable.h>
 | 
						|
 | 
						|
	.text
 | 
						|
 | 
						|
/*
 | 
						|
 * Stackframe:
 | 
						|
 *		
 | 
						|
 *         +-> Back chain			(SP + 256)
 | 
						|
 *         |   General register save area	(SP + 112)
 | 
						|
 *         |   Parameter save area		(SP + 48)
 | 
						|
 *         |   TOC save area			(SP + 40)
 | 
						|
 *         |   link editor doubleword		(SP + 32)
 | 
						|
 *         |   compiler doubleword		(SP + 24)
 | 
						|
 *         |   LR save area			(SP + 16)
 | 
						|
 *         |   CR save area			(SP + 8)
 | 
						|
 * SP ---> +-- Back chain			(SP + 0)
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef CONFIG_PPC_64K_PAGES
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
 *                                                                           *
 | 
						|
 *           4K SW & 4K HW pages implementation                              *
 | 
						|
 *                                                                           *
 | 
						|
 *****************************************************************************/
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 | 
						|
 *		 pte_t *ptep, unsigned long trap, int local, int ssize)
 | 
						|
 *
 | 
						|
 * Adds a 4K page to the hash table in a segment of 4K pages only
 | 
						|
 */
 | 
						|
 | 
						|
_GLOBAL(__hash_page_4K)
 | 
						|
	mflr	r0
 | 
						|
	std	r0,16(r1)
 | 
						|
	stdu	r1,-STACKFRAMESIZE(r1)
 | 
						|
	/* Save all params that we need after a function call */
 | 
						|
	std	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r8,STK_PARAM(R8)(r1)
 | 
						|
	std	r9,STK_PARAM(R9)(r1)
 | 
						|
	
 | 
						|
	/* Save non-volatile registers.
 | 
						|
	 * r31 will hold "old PTE"
 | 
						|
	 * r30 is "new PTE"
 | 
						|
	 * r29 is vpn
 | 
						|
	 * r28 is a hash value
 | 
						|
	 * r27 is hashtab mask (maybe dynamic patched instead ?)
 | 
						|
	 */
 | 
						|
	std	r27,STK_REG(R27)(r1)
 | 
						|
	std	r28,STK_REG(R28)(r1)
 | 
						|
	std	r29,STK_REG(R29)(r1)
 | 
						|
	std	r30,STK_REG(R30)(r1)
 | 
						|
	std	r31,STK_REG(R31)(r1)
 | 
						|
	
 | 
						|
	/* Step 1:
 | 
						|
	 *
 | 
						|
	 * Check permissions, atomically mark the linux PTE busy
 | 
						|
	 * and hashed.
 | 
						|
	 */ 
 | 
						|
1:
 | 
						|
	ldarx	r31,0,r6
 | 
						|
	/* Check access rights (access & ~(pte_val(*ptep))) */
 | 
						|
	andc.	r0,r4,r31
 | 
						|
	bne-	htab_wrong_access
 | 
						|
	/* Check if PTE is busy */
 | 
						|
	andi.	r0,r31,_PAGE_BUSY
 | 
						|
	/* If so, just bail out and refault if needed. Someone else
 | 
						|
	 * is changing this PTE anyway and might hash it.
 | 
						|
	 */
 | 
						|
	bne-	htab_bail_ok
 | 
						|
 | 
						|
	/* Prepare new PTE value (turn access RW into DIRTY, then
 | 
						|
	 * add BUSY,HASHPTE and ACCESSED)
 | 
						|
	 */
 | 
						|
	rlwinm	r30,r4,32-9+7,31-7,31-7	/* _PAGE_RW -> _PAGE_DIRTY */
 | 
						|
	or	r30,r30,r31
 | 
						|
	ori	r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
 | 
						|
	/* Write the linux PTE atomically (setting busy) */
 | 
						|
	stdcx.	r30,0,r6
 | 
						|
	bne-	1b
 | 
						|
	isync
 | 
						|
 | 
						|
	/* Step 2:
 | 
						|
	 *
 | 
						|
	 * Insert/Update the HPTE in the hash table. At this point,
 | 
						|
	 * r4 (access) is re-useable, we use it for the new HPTE flags
 | 
						|
	 */
 | 
						|
 | 
						|
BEGIN_FTR_SECTION
 | 
						|
	cmpdi	r9,0			/* check segment size */
 | 
						|
	bne	3f
 | 
						|
END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
 | 
						|
	/* Calc vpn and put it in r29 */
 | 
						|
	sldi	r29,r5,SID_SHIFT - VPN_SHIFT
 | 
						|
	rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
 | 
						|
	or	r29,r28,r29
 | 
						|
	/*
 | 
						|
	 * Calculate hash value for primary slot and store it in r28
 | 
						|
	 * r3 = va, r5 = vsid
 | 
						|
	 * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
 | 
						|
	 */
 | 
						|
	rldicl	r0,r3,64-12,48
 | 
						|
	xor	r28,r5,r0		/* hash */
 | 
						|
	b	4f
 | 
						|
 | 
						|
3:	/* Calc vpn and put it in r29 */
 | 
						|
	sldi	r29,r5,SID_SHIFT_1T - VPN_SHIFT
 | 
						|
	rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
 | 
						|
	or	r29,r28,r29
 | 
						|
 | 
						|
	/*
 | 
						|
	 * calculate hash value for primary slot and
 | 
						|
	 * store it in r28 for 1T segment
 | 
						|
	 * r3 = va, r5 = vsid
 | 
						|
	 */
 | 
						|
	sldi	r28,r5,25		/* vsid << 25 */
 | 
						|
	/* r0 =  (va >> 12) & ((1ul << (40 - 12)) -1) */
 | 
						|
	rldicl	r0,r3,64-12,36
 | 
						|
	xor	r28,r28,r5		/* vsid ^ ( vsid << 25) */
 | 
						|
	xor	r28,r28,r0		/* hash */
 | 
						|
 | 
						|
	/* Convert linux PTE bits into HW equivalents */
 | 
						|
4:	andi.	r3,r30,0x1fe		/* Get basic set of flags */
 | 
						|
	xori	r3,r3,HPTE_R_N		/* _PAGE_EXEC -> NOEXEC */
 | 
						|
	rlwinm	r0,r30,32-9+1,30,30	/* _PAGE_RW -> _PAGE_USER (r0) */
 | 
						|
	rlwinm	r4,r30,32-7+1,30,30	/* _PAGE_DIRTY -> _PAGE_USER (r4) */
 | 
						|
	and	r0,r0,r4		/* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
 | 
						|
	andc	r0,r30,r0		/* r0 = pte & ~r0 */
 | 
						|
	rlwimi	r3,r0,32-1,31,31	/* Insert result into PP lsb */
 | 
						|
	ori	r3,r3,HPTE_R_C		/* Always add "C" bit for perf. */
 | 
						|
 | 
						|
	/* We eventually do the icache sync here (maybe inline that
 | 
						|
	 * code rather than call a C function...) 
 | 
						|
	 */
 | 
						|
BEGIN_FTR_SECTION
 | 
						|
	mr	r4,r30
 | 
						|
	mr	r5,r7
 | 
						|
	bl	.hash_page_do_lazy_icache
 | 
						|
END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 | 
						|
 | 
						|
	/* At this point, r3 contains new PP bits, save them in
 | 
						|
	 * place of "access" in the param area (sic)
 | 
						|
	 */
 | 
						|
	std	r3,STK_PARAM(R4)(r1)
 | 
						|
 | 
						|
	/* Get htab_hash_mask */
 | 
						|
	ld	r4,htab_hash_mask@got(2)
 | 
						|
	ld	r27,0(r4)	/* htab_hash_mask -> r27 */
 | 
						|
 | 
						|
	/* Check if we may already be in the hashtable, in this case, we
 | 
						|
	 * go to out-of-line code to try to modify the HPTE
 | 
						|
	 */
 | 
						|
	andi.	r0,r31,_PAGE_HASHPTE
 | 
						|
	bne	htab_modify_pte
 | 
						|
 | 
						|
htab_insert_pte:
 | 
						|
	/* Clear hpte bits in new pte (we also clear BUSY btw) and
 | 
						|
	 * add _PAGE_HASHPTE
 | 
						|
	 */
 | 
						|
	lis	r0,_PAGE_HPTEFLAGS@h
 | 
						|
	ori	r0,r0,_PAGE_HPTEFLAGS@l
 | 
						|
	andc	r30,r30,r0
 | 
						|
	ori	r30,r30,_PAGE_HASHPTE
 | 
						|
 | 
						|
	/* physical address r5 */
 | 
						|
	rldicl	r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
 | 
						|
	sldi	r5,r5,PAGE_SHIFT
 | 
						|
 | 
						|
	/* Calculate primary group hash */
 | 
						|
	and	r0,r28,r27
 | 
						|
	rldicr	r3,r0,3,63-3		/* r3 = (hash & mask) << 3 */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_insert */
 | 
						|
	ld	r6,STK_PARAM(R4)(r1)	/* Retrieve new pp bits */
 | 
						|
	mr	r4,r29			/* Retrieve vpn */
 | 
						|
	li	r7,0			/* !bolted, !secondary */
 | 
						|
	li	r8,MMU_PAGE_4K		/* page size */
 | 
						|
	ld	r9,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
_GLOBAL(htab_call_hpte_insert1)
 | 
						|
	bl	.			/* Patched by htab_finish_init() */
 | 
						|
	cmpdi	0,r3,0
 | 
						|
	bge	htab_pte_insert_ok	/* Insertion successful */
 | 
						|
	cmpdi	0,r3,-2			/* Critical failure */
 | 
						|
	beq-	htab_pte_insert_failure
 | 
						|
 | 
						|
	/* Now try secondary slot */
 | 
						|
	
 | 
						|
	/* physical address r5 */
 | 
						|
	rldicl	r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
 | 
						|
	sldi	r5,r5,PAGE_SHIFT
 | 
						|
 | 
						|
	/* Calculate secondary group hash */
 | 
						|
	andc	r0,r27,r28
 | 
						|
	rldicr	r3,r0,3,63-3	/* r0 = (~hash & mask) << 3 */
 | 
						|
	
 | 
						|
	/* Call ppc_md.hpte_insert */
 | 
						|
	ld	r6,STK_PARAM(R4)(r1)	/* Retrieve new pp bits */
 | 
						|
	mr	r4,r29			/* Retrieve vpn */
 | 
						|
	li	r7,HPTE_V_SECONDARY	/* !bolted, secondary */
 | 
						|
	li	r8,MMU_PAGE_4K		/* page size */
 | 
						|
	ld	r9,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
_GLOBAL(htab_call_hpte_insert2)
 | 
						|
	bl	.			/* Patched by htab_finish_init() */
 | 
						|
	cmpdi	0,r3,0
 | 
						|
	bge+	htab_pte_insert_ok	/* Insertion successful */
 | 
						|
	cmpdi	0,r3,-2			/* Critical failure */
 | 
						|
	beq-	htab_pte_insert_failure
 | 
						|
 | 
						|
	/* Both are full, we need to evict something */
 | 
						|
	mftb	r0
 | 
						|
	/* Pick a random group based on TB */
 | 
						|
	andi.	r0,r0,1
 | 
						|
	mr	r5,r28
 | 
						|
	bne	2f
 | 
						|
	not	r5,r5
 | 
						|
2:	and	r0,r5,r27
 | 
						|
	rldicr	r3,r0,3,63-3	/* r0 = (hash & mask) << 3 */	
 | 
						|
	/* Call ppc_md.hpte_remove */
 | 
						|
_GLOBAL(htab_call_hpte_remove)
 | 
						|
	bl	.			/* Patched by htab_finish_init() */
 | 
						|
 | 
						|
	/* Try all again */
 | 
						|
	b	htab_insert_pte	
 | 
						|
 | 
						|
htab_bail_ok:
 | 
						|
	li	r3,0
 | 
						|
	b	htab_bail
 | 
						|
 | 
						|
htab_pte_insert_ok:
 | 
						|
	/* Insert slot number & secondary bit in PTE */
 | 
						|
	rldimi	r30,r3,12,63-15
 | 
						|
		
 | 
						|
	/* Write out the PTE with a normal write
 | 
						|
	 * (maybe add eieio may be good still ?)
 | 
						|
	 */
 | 
						|
htab_write_out_pte:
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r30,0(r6)
 | 
						|
	li	r3, 0
 | 
						|
htab_bail:
 | 
						|
	ld	r27,STK_REG(R27)(r1)
 | 
						|
	ld	r28,STK_REG(R28)(r1)
 | 
						|
	ld	r29,STK_REG(R29)(r1)
 | 
						|
	ld      r30,STK_REG(R30)(r1)
 | 
						|
	ld      r31,STK_REG(R31)(r1)
 | 
						|
	addi    r1,r1,STACKFRAMESIZE
 | 
						|
	ld      r0,16(r1)
 | 
						|
	mtlr    r0
 | 
						|
	blr
 | 
						|
 | 
						|
htab_modify_pte:
 | 
						|
	/* Keep PP bits in r4 and slot idx from the PTE around in r3 */
 | 
						|
	mr	r4,r3
 | 
						|
	rlwinm	r3,r31,32-12,29,31
 | 
						|
 | 
						|
	/* Secondary group ? if yes, get a inverted hash value */
 | 
						|
	mr	r5,r28
 | 
						|
	andi.	r0,r31,_PAGE_SECONDARY
 | 
						|
	beq	1f
 | 
						|
	not	r5,r5
 | 
						|
1:
 | 
						|
	/* Calculate proper slot value for ppc_md.hpte_updatepp */
 | 
						|
	and	r0,r5,r27
 | 
						|
	rldicr	r0,r0,3,63-3	/* r0 = (hash & mask) << 3 */
 | 
						|
	add	r3,r0,r3	/* add slot idx */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_updatepp */
 | 
						|
	mr	r5,r29			/* vpn */
 | 
						|
	li	r6,MMU_PAGE_4K		/* page size */
 | 
						|
	ld	r7,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
	ld	r8,STK_PARAM(R8)(r1)	/* get "local" param */
 | 
						|
_GLOBAL(htab_call_hpte_updatepp)
 | 
						|
	bl	.			/* Patched by htab_finish_init() */
 | 
						|
 | 
						|
	/* if we failed because typically the HPTE wasn't really here
 | 
						|
	 * we try an insertion. 
 | 
						|
	 */
 | 
						|
	cmpdi	0,r3,-1
 | 
						|
	beq-	htab_insert_pte
 | 
						|
 | 
						|
	/* Clear the BUSY bit and Write out the PTE */
 | 
						|
	li	r0,_PAGE_BUSY
 | 
						|
	andc	r30,r30,r0
 | 
						|
	b	htab_write_out_pte
 | 
						|
 | 
						|
htab_wrong_access:
 | 
						|
	/* Bail out clearing reservation */
 | 
						|
	stdcx.	r31,0,r6
 | 
						|
	li	r3,1
 | 
						|
	b	htab_bail
 | 
						|
 | 
						|
htab_pte_insert_failure:
 | 
						|
	/* Bail out restoring old PTE */
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r31,0(r6)
 | 
						|
	li	r3,-1
 | 
						|
	b	htab_bail
 | 
						|
 | 
						|
 | 
						|
#else /* CONFIG_PPC_64K_PAGES */
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
 *                                                                           *
 | 
						|
 *           64K SW & 4K or 64K HW in a 4K segment pages implementation      *
 | 
						|
 *                                                                           *
 | 
						|
 *****************************************************************************/
 | 
						|
 | 
						|
/* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 | 
						|
 *		 pte_t *ptep, unsigned long trap, int local, int ssize,
 | 
						|
 *		 int subpg_prot)
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * For now, we do NOT implement Admixed pages
 | 
						|
 */
 | 
						|
_GLOBAL(__hash_page_4K)
 | 
						|
	mflr	r0
 | 
						|
	std	r0,16(r1)
 | 
						|
	stdu	r1,-STACKFRAMESIZE(r1)
 | 
						|
	/* Save all params that we need after a function call */
 | 
						|
	std	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r8,STK_PARAM(R8)(r1)
 | 
						|
	std	r9,STK_PARAM(R9)(r1)
 | 
						|
 | 
						|
	/* Save non-volatile registers.
 | 
						|
	 * r31 will hold "old PTE"
 | 
						|
	 * r30 is "new PTE"
 | 
						|
	 * r29 is vpn
 | 
						|
	 * r28 is a hash value
 | 
						|
	 * r27 is hashtab mask (maybe dynamic patched instead ?)
 | 
						|
	 * r26 is the hidx mask
 | 
						|
	 * r25 is the index in combo page
 | 
						|
	 */
 | 
						|
	std	r25,STK_REG(R25)(r1)
 | 
						|
	std	r26,STK_REG(R26)(r1)
 | 
						|
	std	r27,STK_REG(R27)(r1)
 | 
						|
	std	r28,STK_REG(R28)(r1)
 | 
						|
	std	r29,STK_REG(R29)(r1)
 | 
						|
	std	r30,STK_REG(R30)(r1)
 | 
						|
	std	r31,STK_REG(R31)(r1)
 | 
						|
 | 
						|
	/* Step 1:
 | 
						|
	 *
 | 
						|
	 * Check permissions, atomically mark the linux PTE busy
 | 
						|
	 * and hashed.
 | 
						|
	 */
 | 
						|
1:
 | 
						|
	ldarx	r31,0,r6
 | 
						|
	/* Check access rights (access & ~(pte_val(*ptep))) */
 | 
						|
	andc.	r0,r4,r31
 | 
						|
	bne-	htab_wrong_access
 | 
						|
	/* Check if PTE is busy */
 | 
						|
	andi.	r0,r31,_PAGE_BUSY
 | 
						|
	/* If so, just bail out and refault if needed. Someone else
 | 
						|
	 * is changing this PTE anyway and might hash it.
 | 
						|
	 */
 | 
						|
	bne-	htab_bail_ok
 | 
						|
	/* Prepare new PTE value (turn access RW into DIRTY, then
 | 
						|
	 * add BUSY and ACCESSED)
 | 
						|
	 */
 | 
						|
	rlwinm	r30,r4,32-9+7,31-7,31-7	/* _PAGE_RW -> _PAGE_DIRTY */
 | 
						|
	or	r30,r30,r31
 | 
						|
	ori	r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
 | 
						|
	oris	r30,r30,_PAGE_COMBO@h
 | 
						|
	/* Write the linux PTE atomically (setting busy) */
 | 
						|
	stdcx.	r30,0,r6
 | 
						|
	bne-	1b
 | 
						|
	isync
 | 
						|
 | 
						|
	/* Step 2:
 | 
						|
	 *
 | 
						|
	 * Insert/Update the HPTE in the hash table. At this point,
 | 
						|
	 * r4 (access) is re-useable, we use it for the new HPTE flags
 | 
						|
	 */
 | 
						|
 | 
						|
	/* Load the hidx index */
 | 
						|
	rldicl	r25,r3,64-12,60
 | 
						|
 | 
						|
BEGIN_FTR_SECTION
 | 
						|
	cmpdi	r9,0			/* check segment size */
 | 
						|
	bne	3f
 | 
						|
END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
 | 
						|
	/* Calc vpn and put it in r29 */
 | 
						|
	sldi	r29,r5,SID_SHIFT - VPN_SHIFT
 | 
						|
	/*
 | 
						|
	 * clrldi r3,r3,64 - SID_SHIFT -->  ea & 0xfffffff
 | 
						|
	 * srdi	 r28,r3,VPN_SHIFT
 | 
						|
	 */
 | 
						|
	rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
 | 
						|
	or	r29,r28,r29
 | 
						|
	/*
 | 
						|
	 * Calculate hash value for primary slot and store it in r28
 | 
						|
	 * r3 = va, r5 = vsid
 | 
						|
	 * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
 | 
						|
	 */
 | 
						|
	rldicl	r0,r3,64-12,48
 | 
						|
	xor	r28,r5,r0		/* hash */
 | 
						|
	b	4f
 | 
						|
 | 
						|
3:	/* Calc vpn and put it in r29 */
 | 
						|
	sldi	r29,r5,SID_SHIFT_1T - VPN_SHIFT
 | 
						|
	/*
 | 
						|
	 * clrldi r3,r3,64 - SID_SHIFT_1T -->  ea & 0xffffffffff
 | 
						|
	 * srdi	r28,r3,VPN_SHIFT
 | 
						|
	 */
 | 
						|
	rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
 | 
						|
	or	r29,r28,r29
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Calculate hash value for primary slot and
 | 
						|
	 * store it in r28  for 1T segment
 | 
						|
	 * r3 = va, r5 = vsid
 | 
						|
	 */
 | 
						|
	sldi	r28,r5,25		/* vsid << 25 */
 | 
						|
	/* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */
 | 
						|
	rldicl	r0,r3,64-12,36
 | 
						|
	xor	r28,r28,r5		/* vsid ^ ( vsid << 25) */
 | 
						|
	xor	r28,r28,r0		/* hash */
 | 
						|
 | 
						|
	/* Convert linux PTE bits into HW equivalents */
 | 
						|
4:
 | 
						|
#ifdef CONFIG_PPC_SUBPAGE_PROT
 | 
						|
	andc	r10,r30,r10
 | 
						|
	andi.	r3,r10,0x1fe		/* Get basic set of flags */
 | 
						|
	rlwinm	r0,r10,32-9+1,30,30	/* _PAGE_RW -> _PAGE_USER (r0) */
 | 
						|
#else
 | 
						|
	andi.	r3,r30,0x1fe		/* Get basic set of flags */
 | 
						|
	rlwinm	r0,r30,32-9+1,30,30	/* _PAGE_RW -> _PAGE_USER (r0) */
 | 
						|
#endif
 | 
						|
	xori	r3,r3,HPTE_R_N		/* _PAGE_EXEC -> NOEXEC */
 | 
						|
	rlwinm	r4,r30,32-7+1,30,30	/* _PAGE_DIRTY -> _PAGE_USER (r4) */
 | 
						|
	and	r0,r0,r4		/* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
 | 
						|
	andc	r0,r3,r0		/* r0 = pte & ~r0 */
 | 
						|
	rlwimi	r3,r0,32-1,31,31	/* Insert result into PP lsb */
 | 
						|
	ori	r3,r3,HPTE_R_C		/* Always add "C" bit for perf. */
 | 
						|
 | 
						|
	/* We eventually do the icache sync here (maybe inline that
 | 
						|
	 * code rather than call a C function...)
 | 
						|
	 */
 | 
						|
BEGIN_FTR_SECTION
 | 
						|
	mr	r4,r30
 | 
						|
	mr	r5,r7
 | 
						|
	bl	.hash_page_do_lazy_icache
 | 
						|
END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 | 
						|
 | 
						|
	/* At this point, r3 contains new PP bits, save them in
 | 
						|
	 * place of "access" in the param area (sic)
 | 
						|
	 */
 | 
						|
	std	r3,STK_PARAM(R4)(r1)
 | 
						|
 | 
						|
	/* Get htab_hash_mask */
 | 
						|
	ld	r4,htab_hash_mask@got(2)
 | 
						|
	ld	r27,0(r4)	/* htab_hash_mask -> r27 */
 | 
						|
 | 
						|
	/* Check if we may already be in the hashtable, in this case, we
 | 
						|
	 * go to out-of-line code to try to modify the HPTE. We look for
 | 
						|
	 * the bit at (1 >> (index + 32))
 | 
						|
	 */
 | 
						|
	rldicl.	r0,r31,64-12,48
 | 
						|
	li	r26,0			/* Default hidx */
 | 
						|
	beq	htab_insert_pte
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Check if the pte was already inserted into the hash table
 | 
						|
	 * as a 64k HW page, and invalidate the 64k HPTE if so.
 | 
						|
	 */
 | 
						|
	andis.	r0,r31,_PAGE_COMBO@h
 | 
						|
	beq	htab_inval_old_hpte
 | 
						|
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	ori	r26,r6,0x8000		/* Load the hidx mask */
 | 
						|
	ld	r26,0(r26)
 | 
						|
	addi	r5,r25,36		/* Check actual HPTE_SUB bit, this */
 | 
						|
	rldcr.	r0,r31,r5,0		/* must match pgtable.h definition */
 | 
						|
	bne	htab_modify_pte
 | 
						|
 | 
						|
htab_insert_pte:
 | 
						|
	/* real page number in r5, PTE RPN value + index */
 | 
						|
	andis.	r0,r31,_PAGE_4K_PFN@h
 | 
						|
	srdi	r5,r31,PTE_RPN_SHIFT
 | 
						|
	bne-	htab_special_pfn
 | 
						|
	sldi	r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
 | 
						|
	add	r5,r5,r25
 | 
						|
htab_special_pfn:
 | 
						|
	sldi	r5,r5,HW_PAGE_SHIFT
 | 
						|
 | 
						|
	/* Calculate primary group hash */
 | 
						|
	and	r0,r28,r27
 | 
						|
	rldicr	r3,r0,3,63-3		/* r0 = (hash & mask) << 3 */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_insert */
 | 
						|
	ld	r6,STK_PARAM(R4)(r1)	/* Retrieve new pp bits */
 | 
						|
	mr	r4,r29			/* Retrieve vpn */
 | 
						|
	li	r7,0			/* !bolted, !secondary */
 | 
						|
	li	r8,MMU_PAGE_4K		/* page size */
 | 
						|
	ld	r9,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
_GLOBAL(htab_call_hpte_insert1)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
	cmpdi	0,r3,0
 | 
						|
	bge	htab_pte_insert_ok	/* Insertion successful */
 | 
						|
	cmpdi	0,r3,-2			/* Critical failure */
 | 
						|
	beq-	htab_pte_insert_failure
 | 
						|
 | 
						|
	/* Now try secondary slot */
 | 
						|
 | 
						|
	/* real page number in r5, PTE RPN value + index */
 | 
						|
	andis.	r0,r31,_PAGE_4K_PFN@h
 | 
						|
	srdi	r5,r31,PTE_RPN_SHIFT
 | 
						|
	bne-	3f
 | 
						|
	sldi	r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
 | 
						|
	add	r5,r5,r25
 | 
						|
3:	sldi	r5,r5,HW_PAGE_SHIFT
 | 
						|
 | 
						|
	/* Calculate secondary group hash */
 | 
						|
	andc	r0,r27,r28
 | 
						|
	rldicr	r3,r0,3,63-3		/* r0 = (~hash & mask) << 3 */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_insert */
 | 
						|
	ld	r6,STK_PARAM(R4)(r1)	/* Retrieve new pp bits */
 | 
						|
	mr	r4,r29			/* Retrieve vpn */
 | 
						|
	li	r7,HPTE_V_SECONDARY	/* !bolted, secondary */
 | 
						|
	li	r8,MMU_PAGE_4K		/* page size */
 | 
						|
	ld	r9,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
_GLOBAL(htab_call_hpte_insert2)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
	cmpdi	0,r3,0
 | 
						|
	bge+	htab_pte_insert_ok	/* Insertion successful */
 | 
						|
	cmpdi	0,r3,-2			/* Critical failure */
 | 
						|
	beq-	htab_pte_insert_failure
 | 
						|
 | 
						|
	/* Both are full, we need to evict something */
 | 
						|
	mftb	r0
 | 
						|
	/* Pick a random group based on TB */
 | 
						|
	andi.	r0,r0,1
 | 
						|
	mr	r5,r28
 | 
						|
	bne	2f
 | 
						|
	not	r5,r5
 | 
						|
2:	and	r0,r5,r27
 | 
						|
	rldicr	r3,r0,3,63-3		/* r0 = (hash & mask) << 3 */
 | 
						|
	/* Call ppc_md.hpte_remove */
 | 
						|
_GLOBAL(htab_call_hpte_remove)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
 | 
						|
	/* Try all again */
 | 
						|
	b	htab_insert_pte
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Call out to C code to invalidate an 64k HW HPTE that is
 | 
						|
	 * useless now that the segment has been switched to 4k pages.
 | 
						|
	 */
 | 
						|
htab_inval_old_hpte:
 | 
						|
	mr	r3,r29			/* vpn */
 | 
						|
	mr	r4,r31			/* PTE.pte */
 | 
						|
	li	r5,0			/* PTE.hidx */
 | 
						|
	li	r6,MMU_PAGE_64K		/* psize */
 | 
						|
	ld	r7,STK_PARAM(R9)(r1)	/* ssize */
 | 
						|
	ld	r8,STK_PARAM(R8)(r1)	/* local */
 | 
						|
	bl	.flush_hash_page
 | 
						|
	/* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */
 | 
						|
	lis	r0,_PAGE_HPTE_SUB@h
 | 
						|
	ori	r0,r0,_PAGE_HPTE_SUB@l
 | 
						|
	andc	r30,r30,r0
 | 
						|
	b	htab_insert_pte
 | 
						|
	
 | 
						|
htab_bail_ok:
 | 
						|
	li	r3,0
 | 
						|
	b	htab_bail
 | 
						|
 | 
						|
htab_pte_insert_ok:
 | 
						|
	/* Insert slot number & secondary bit in PTE second half,
 | 
						|
	 * clear _PAGE_BUSY and set approriate HPTE slot bit
 | 
						|
	 */
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	li	r0,_PAGE_BUSY
 | 
						|
	andc	r30,r30,r0
 | 
						|
	/* HPTE SUB bit */
 | 
						|
	li	r0,1
 | 
						|
	subfic	r5,r25,27		/* Must match bit position in */
 | 
						|
	sld	r0,r0,r5		/* pgtable.h */
 | 
						|
	or	r30,r30,r0
 | 
						|
	/* hindx */
 | 
						|
	sldi	r5,r25,2
 | 
						|
	sld	r3,r3,r5
 | 
						|
	li	r4,0xf
 | 
						|
	sld	r4,r4,r5
 | 
						|
	andc	r26,r26,r4
 | 
						|
	or	r26,r26,r3
 | 
						|
	ori	r5,r6,0x8000
 | 
						|
	std	r26,0(r5)
 | 
						|
	lwsync
 | 
						|
	std	r30,0(r6)
 | 
						|
	li	r3, 0
 | 
						|
htab_bail:
 | 
						|
	ld	r25,STK_REG(R25)(r1)
 | 
						|
	ld	r26,STK_REG(R26)(r1)
 | 
						|
	ld	r27,STK_REG(R27)(r1)
 | 
						|
	ld	r28,STK_REG(R28)(r1)
 | 
						|
	ld	r29,STK_REG(R29)(r1)
 | 
						|
	ld      r30,STK_REG(R30)(r1)
 | 
						|
	ld      r31,STK_REG(R31)(r1)
 | 
						|
	addi    r1,r1,STACKFRAMESIZE
 | 
						|
	ld      r0,16(r1)
 | 
						|
	mtlr    r0
 | 
						|
	blr
 | 
						|
 | 
						|
htab_modify_pte:
 | 
						|
	/* Keep PP bits in r4 and slot idx from the PTE around in r3 */
 | 
						|
	mr	r4,r3
 | 
						|
	sldi	r5,r25,2
 | 
						|
	srd	r3,r26,r5
 | 
						|
 | 
						|
	/* Secondary group ? if yes, get a inverted hash value */
 | 
						|
	mr	r5,r28
 | 
						|
	andi.	r0,r3,0x8 /* page secondary ? */
 | 
						|
	beq	1f
 | 
						|
	not	r5,r5
 | 
						|
1:	andi.	r3,r3,0x7 /* extract idx alone */
 | 
						|
 | 
						|
	/* Calculate proper slot value for ppc_md.hpte_updatepp */
 | 
						|
	and	r0,r5,r27
 | 
						|
	rldicr	r0,r0,3,63-3	/* r0 = (hash & mask) << 3 */
 | 
						|
	add	r3,r0,r3	/* add slot idx */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_updatepp */
 | 
						|
	mr	r5,r29			/* vpn */
 | 
						|
	li	r6,MMU_PAGE_4K		/* page size */
 | 
						|
	ld	r7,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
	ld	r8,STK_PARAM(R8)(r1)	/* get "local" param */
 | 
						|
_GLOBAL(htab_call_hpte_updatepp)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
 | 
						|
	/* if we failed because typically the HPTE wasn't really here
 | 
						|
	 * we try an insertion.
 | 
						|
	 */
 | 
						|
	cmpdi	0,r3,-1
 | 
						|
	beq-	htab_insert_pte
 | 
						|
 | 
						|
	/* Clear the BUSY bit and Write out the PTE */
 | 
						|
	li	r0,_PAGE_BUSY
 | 
						|
	andc	r30,r30,r0
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r30,0(r6)
 | 
						|
	li	r3,0
 | 
						|
	b	htab_bail
 | 
						|
 | 
						|
htab_wrong_access:
 | 
						|
	/* Bail out clearing reservation */
 | 
						|
	stdcx.	r31,0,r6
 | 
						|
	li	r3,1
 | 
						|
	b	htab_bail
 | 
						|
 | 
						|
htab_pte_insert_failure:
 | 
						|
	/* Bail out restoring old PTE */
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r31,0(r6)
 | 
						|
	li	r3,-1
 | 
						|
	b	htab_bail
 | 
						|
 | 
						|
#endif /* CONFIG_PPC_64K_PAGES */
 | 
						|
 | 
						|
#ifdef CONFIG_PPC_HAS_HASH_64K
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
 *                                                                           *
 | 
						|
 *           64K SW & 64K HW in a 64K segment pages implementation           *
 | 
						|
 *                                                                           *
 | 
						|
 *****************************************************************************/
 | 
						|
 | 
						|
_GLOBAL(__hash_page_64K)
 | 
						|
	mflr	r0
 | 
						|
	std	r0,16(r1)
 | 
						|
	stdu	r1,-STACKFRAMESIZE(r1)
 | 
						|
	/* Save all params that we need after a function call */
 | 
						|
	std	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r8,STK_PARAM(R8)(r1)
 | 
						|
	std	r9,STK_PARAM(R9)(r1)
 | 
						|
 | 
						|
	/* Save non-volatile registers.
 | 
						|
	 * r31 will hold "old PTE"
 | 
						|
	 * r30 is "new PTE"
 | 
						|
	 * r29 is vpn
 | 
						|
	 * r28 is a hash value
 | 
						|
	 * r27 is hashtab mask (maybe dynamic patched instead ?)
 | 
						|
	 */
 | 
						|
	std	r27,STK_REG(R27)(r1)
 | 
						|
	std	r28,STK_REG(R28)(r1)
 | 
						|
	std	r29,STK_REG(R29)(r1)
 | 
						|
	std	r30,STK_REG(R30)(r1)
 | 
						|
	std	r31,STK_REG(R31)(r1)
 | 
						|
 | 
						|
	/* Step 1:
 | 
						|
	 *
 | 
						|
	 * Check permissions, atomically mark the linux PTE busy
 | 
						|
	 * and hashed.
 | 
						|
	 */
 | 
						|
1:
 | 
						|
	ldarx	r31,0,r6
 | 
						|
	/* Check access rights (access & ~(pte_val(*ptep))) */
 | 
						|
	andc.	r0,r4,r31
 | 
						|
	bne-	ht64_wrong_access
 | 
						|
	/* Check if PTE is busy */
 | 
						|
	andi.	r0,r31,_PAGE_BUSY
 | 
						|
	/* If so, just bail out and refault if needed. Someone else
 | 
						|
	 * is changing this PTE anyway and might hash it.
 | 
						|
	 */
 | 
						|
	bne-	ht64_bail_ok
 | 
						|
BEGIN_FTR_SECTION
 | 
						|
	/* Check if PTE has the cache-inhibit bit set */
 | 
						|
	andi.	r0,r31,_PAGE_NO_CACHE
 | 
						|
	/* If so, bail out and refault as a 4k page */
 | 
						|
	bne-	ht64_bail_ok
 | 
						|
END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)
 | 
						|
	/* Prepare new PTE value (turn access RW into DIRTY, then
 | 
						|
	 * add BUSY and ACCESSED)
 | 
						|
	 */
 | 
						|
	rlwinm	r30,r4,32-9+7,31-7,31-7	/* _PAGE_RW -> _PAGE_DIRTY */
 | 
						|
	or	r30,r30,r31
 | 
						|
	ori	r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
 | 
						|
	/* Write the linux PTE atomically (setting busy) */
 | 
						|
	stdcx.	r30,0,r6
 | 
						|
	bne-	1b
 | 
						|
	isync
 | 
						|
 | 
						|
	/* Step 2:
 | 
						|
	 *
 | 
						|
	 * Insert/Update the HPTE in the hash table. At this point,
 | 
						|
	 * r4 (access) is re-useable, we use it for the new HPTE flags
 | 
						|
	 */
 | 
						|
 | 
						|
BEGIN_FTR_SECTION
 | 
						|
	cmpdi	r9,0			/* check segment size */
 | 
						|
	bne	3f
 | 
						|
END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
 | 
						|
	/* Calc vpn and put it in r29 */
 | 
						|
	sldi	r29,r5,SID_SHIFT - VPN_SHIFT
 | 
						|
	rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
 | 
						|
	or	r29,r28,r29
 | 
						|
 | 
						|
	/* Calculate hash value for primary slot and store it in r28
 | 
						|
	 * r3 = va, r5 = vsid
 | 
						|
	 * r0 = (va >> 16) & ((1ul << (28 - 16)) -1)
 | 
						|
	 */
 | 
						|
	rldicl	r0,r3,64-16,52
 | 
						|
	xor	r28,r5,r0		/* hash */
 | 
						|
	b	4f
 | 
						|
 | 
						|
3:	/* Calc vpn and put it in r29 */
 | 
						|
	sldi	r29,r5,SID_SHIFT_1T - VPN_SHIFT
 | 
						|
	rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
 | 
						|
	or	r29,r28,r29
 | 
						|
	/*
 | 
						|
	 * calculate hash value for primary slot and
 | 
						|
	 * store it in r28 for 1T segment
 | 
						|
	 * r3 = va, r5 = vsid
 | 
						|
	 */
 | 
						|
	sldi	r28,r5,25		/* vsid << 25 */
 | 
						|
	/* r0 = (va >> 16) & ((1ul << (40 - 16)) -1) */
 | 
						|
	rldicl	r0,r3,64-16,40
 | 
						|
	xor	r28,r28,r5		/* vsid ^ ( vsid << 25) */
 | 
						|
	xor	r28,r28,r0		/* hash */
 | 
						|
 | 
						|
	/* Convert linux PTE bits into HW equivalents */
 | 
						|
4:	andi.	r3,r30,0x1fe		/* Get basic set of flags */
 | 
						|
	xori	r3,r3,HPTE_R_N		/* _PAGE_EXEC -> NOEXEC */
 | 
						|
	rlwinm	r0,r30,32-9+1,30,30	/* _PAGE_RW -> _PAGE_USER (r0) */
 | 
						|
	rlwinm	r4,r30,32-7+1,30,30	/* _PAGE_DIRTY -> _PAGE_USER (r4) */
 | 
						|
	and	r0,r0,r4		/* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
 | 
						|
	andc	r0,r30,r0		/* r0 = pte & ~r0 */
 | 
						|
	rlwimi	r3,r0,32-1,31,31	/* Insert result into PP lsb */
 | 
						|
	ori	r3,r3,HPTE_R_C		/* Always add "C" bit for perf. */
 | 
						|
 | 
						|
	/* We eventually do the icache sync here (maybe inline that
 | 
						|
	 * code rather than call a C function...)
 | 
						|
	 */
 | 
						|
BEGIN_FTR_SECTION
 | 
						|
	mr	r4,r30
 | 
						|
	mr	r5,r7
 | 
						|
	bl	.hash_page_do_lazy_icache
 | 
						|
END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 | 
						|
 | 
						|
	/* At this point, r3 contains new PP bits, save them in
 | 
						|
	 * place of "access" in the param area (sic)
 | 
						|
	 */
 | 
						|
	std	r3,STK_PARAM(R4)(r1)
 | 
						|
 | 
						|
	/* Get htab_hash_mask */
 | 
						|
	ld	r4,htab_hash_mask@got(2)
 | 
						|
	ld	r27,0(r4)	/* htab_hash_mask -> r27 */
 | 
						|
 | 
						|
	/* Check if we may already be in the hashtable, in this case, we
 | 
						|
	 * go to out-of-line code to try to modify the HPTE
 | 
						|
	 */
 | 
						|
	rldicl.	r0,r31,64-12,48
 | 
						|
	bne	ht64_modify_pte
 | 
						|
 | 
						|
ht64_insert_pte:
 | 
						|
	/* Clear hpte bits in new pte (we also clear BUSY btw) and
 | 
						|
	 * add _PAGE_HPTE_SUB0
 | 
						|
	 */
 | 
						|
	lis	r0,_PAGE_HPTEFLAGS@h
 | 
						|
	ori	r0,r0,_PAGE_HPTEFLAGS@l
 | 
						|
	andc	r30,r30,r0
 | 
						|
#ifdef CONFIG_PPC_64K_PAGES
 | 
						|
	oris	r30,r30,_PAGE_HPTE_SUB0@h
 | 
						|
#else
 | 
						|
	ori	r30,r30,_PAGE_HASHPTE
 | 
						|
#endif
 | 
						|
	/* Phyical address in r5 */
 | 
						|
	rldicl	r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
 | 
						|
	sldi	r5,r5,PAGE_SHIFT
 | 
						|
 | 
						|
	/* Calculate primary group hash */
 | 
						|
	and	r0,r28,r27
 | 
						|
	rldicr	r3,r0,3,63-3	/* r0 = (hash & mask) << 3 */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_insert */
 | 
						|
	ld	r6,STK_PARAM(R4)(r1)	/* Retrieve new pp bits */
 | 
						|
	mr	r4,r29			/* Retrieve vpn */
 | 
						|
	li	r7,0			/* !bolted, !secondary */
 | 
						|
	li	r8,MMU_PAGE_64K
 | 
						|
	ld	r9,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
_GLOBAL(ht64_call_hpte_insert1)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
	cmpdi	0,r3,0
 | 
						|
	bge	ht64_pte_insert_ok	/* Insertion successful */
 | 
						|
	cmpdi	0,r3,-2			/* Critical failure */
 | 
						|
	beq-	ht64_pte_insert_failure
 | 
						|
 | 
						|
	/* Now try secondary slot */
 | 
						|
 | 
						|
	/* Phyical address in r5 */
 | 
						|
	rldicl	r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
 | 
						|
	sldi	r5,r5,PAGE_SHIFT
 | 
						|
 | 
						|
	/* Calculate secondary group hash */
 | 
						|
	andc	r0,r27,r28
 | 
						|
	rldicr	r3,r0,3,63-3	/* r0 = (~hash & mask) << 3 */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_insert */
 | 
						|
	ld	r6,STK_PARAM(R4)(r1)	/* Retrieve new pp bits */
 | 
						|
	mr	r4,r29			/* Retrieve vpn */
 | 
						|
	li	r7,HPTE_V_SECONDARY	/* !bolted, secondary */
 | 
						|
	li	r8,MMU_PAGE_64K
 | 
						|
	ld	r9,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
_GLOBAL(ht64_call_hpte_insert2)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
	cmpdi	0,r3,0
 | 
						|
	bge+	ht64_pte_insert_ok	/* Insertion successful */
 | 
						|
	cmpdi	0,r3,-2			/* Critical failure */
 | 
						|
	beq-	ht64_pte_insert_failure
 | 
						|
 | 
						|
	/* Both are full, we need to evict something */
 | 
						|
	mftb	r0
 | 
						|
	/* Pick a random group based on TB */
 | 
						|
	andi.	r0,r0,1
 | 
						|
	mr	r5,r28
 | 
						|
	bne	2f
 | 
						|
	not	r5,r5
 | 
						|
2:	and	r0,r5,r27
 | 
						|
	rldicr	r3,r0,3,63-3	/* r0 = (hash & mask) << 3 */
 | 
						|
	/* Call ppc_md.hpte_remove */
 | 
						|
_GLOBAL(ht64_call_hpte_remove)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
 | 
						|
	/* Try all again */
 | 
						|
	b	ht64_insert_pte
 | 
						|
 | 
						|
ht64_bail_ok:
 | 
						|
	li	r3,0
 | 
						|
	b	ht64_bail
 | 
						|
 | 
						|
ht64_pte_insert_ok:
 | 
						|
	/* Insert slot number & secondary bit in PTE */
 | 
						|
	rldimi	r30,r3,12,63-15
 | 
						|
 | 
						|
	/* Write out the PTE with a normal write
 | 
						|
	 * (maybe add eieio may be good still ?)
 | 
						|
	 */
 | 
						|
ht64_write_out_pte:
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r30,0(r6)
 | 
						|
	li	r3, 0
 | 
						|
ht64_bail:
 | 
						|
	ld	r27,STK_REG(R27)(r1)
 | 
						|
	ld	r28,STK_REG(R28)(r1)
 | 
						|
	ld	r29,STK_REG(R29)(r1)
 | 
						|
	ld      r30,STK_REG(R30)(r1)
 | 
						|
	ld      r31,STK_REG(R31)(r1)
 | 
						|
	addi    r1,r1,STACKFRAMESIZE
 | 
						|
	ld      r0,16(r1)
 | 
						|
	mtlr    r0
 | 
						|
	blr
 | 
						|
 | 
						|
ht64_modify_pte:
 | 
						|
	/* Keep PP bits in r4 and slot idx from the PTE around in r3 */
 | 
						|
	mr	r4,r3
 | 
						|
	rlwinm	r3,r31,32-12,29,31
 | 
						|
 | 
						|
	/* Secondary group ? if yes, get a inverted hash value */
 | 
						|
	mr	r5,r28
 | 
						|
	andi.	r0,r31,_PAGE_F_SECOND
 | 
						|
	beq	1f
 | 
						|
	not	r5,r5
 | 
						|
1:
 | 
						|
	/* Calculate proper slot value for ppc_md.hpte_updatepp */
 | 
						|
	and	r0,r5,r27
 | 
						|
	rldicr	r0,r0,3,63-3	/* r0 = (hash & mask) << 3 */
 | 
						|
	add	r3,r0,r3	/* add slot idx */
 | 
						|
 | 
						|
	/* Call ppc_md.hpte_updatepp */
 | 
						|
	mr	r5,r29			/* vpn */
 | 
						|
	li	r6,MMU_PAGE_64K
 | 
						|
	ld	r7,STK_PARAM(R9)(r1)	/* segment size */
 | 
						|
	ld	r8,STK_PARAM(R8)(r1)	/* get "local" param */
 | 
						|
_GLOBAL(ht64_call_hpte_updatepp)
 | 
						|
	bl	.			/* patched by htab_finish_init() */
 | 
						|
 | 
						|
	/* if we failed because typically the HPTE wasn't really here
 | 
						|
	 * we try an insertion.
 | 
						|
	 */
 | 
						|
	cmpdi	0,r3,-1
 | 
						|
	beq-	ht64_insert_pte
 | 
						|
 | 
						|
	/* Clear the BUSY bit and Write out the PTE */
 | 
						|
	li	r0,_PAGE_BUSY
 | 
						|
	andc	r30,r30,r0
 | 
						|
	b	ht64_write_out_pte
 | 
						|
 | 
						|
ht64_wrong_access:
 | 
						|
	/* Bail out clearing reservation */
 | 
						|
	stdcx.	r31,0,r6
 | 
						|
	li	r3,1
 | 
						|
	b	ht64_bail
 | 
						|
 | 
						|
ht64_pte_insert_failure:
 | 
						|
	/* Bail out restoring old PTE */
 | 
						|
	ld	r6,STK_PARAM(R6)(r1)
 | 
						|
	std	r31,0(r6)
 | 
						|
	li	r3,-1
 | 
						|
	b	ht64_bail
 | 
						|
 | 
						|
 | 
						|
#endif /* CONFIG_PPC_HAS_HASH_64K */
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
 *                                                                           *
 | 
						|
 *           Huge pages implementation is in hugetlbpage.c                   *
 | 
						|
 *                                                                           *
 | 
						|
 *****************************************************************************/
 |