diff options
Diffstat (limited to 'arch/sparc/include/asm/tsb.h')
| -rw-r--r-- | arch/sparc/include/asm/tsb.h | 119 | 
1 files changed, 73 insertions, 46 deletions
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h index 83c571d8c8a..90916f955ca 100644 --- a/arch/sparc/include/asm/tsb.h +++ b/arch/sparc/include/asm/tsb.h @@ -133,29 +133,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;  	sub	TSB, 0x8, TSB;   \  	TSB_STORE(TSB, TAG); -#define KTSB_LOAD_QUAD(TSB, REG) \ -	ldda		[TSB] ASI_NUCLEUS_QUAD_LDD, REG; - -#define KTSB_STORE(ADDR, VAL) \ -	stxa		VAL, [ADDR] ASI_N; - -#define KTSB_LOCK_TAG(TSB, REG1, REG2)	\ -99:	lduwa	[TSB] ASI_N, REG1;	\ -	sethi	%hi(TSB_TAG_LOCK_HIGH), REG2;\ -	andcc	REG1, REG2, %g0;	\ -	bne,pn	%icc, 99b;		\ -	 nop;				\ -	casa	[TSB] ASI_N, REG1, REG2;\ -	cmp	REG1, REG2;		\ -	bne,pn	%icc, 99b;		\ -	 nop;				\ - -#define KTSB_WRITE(TSB, TTE, TAG) \ -	add	TSB, 0x8, TSB;   \ -	stxa	TTE, [TSB] ASI_N;     \ -	sub	TSB, 0x8, TSB;   \ -	stxa	TAG, [TSB] ASI_N; -  	/* Do a kernel page table walk.  Leaves physical PTE pointer in  	 * REG1.  Jumps to FAIL_LABEL on early page table walk termination.  	 * VADDR will not be clobbered, but REG2 will. @@ -165,45 +142,75 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;  	or		REG1, %lo(swapper_pg_dir), REG1; \  	sllx		VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \  	srlx		REG2, 64 - PAGE_SHIFT, REG2; \ -	andn		REG2, 0x3, REG2; \ -	lduw		[REG1 + REG2], REG1; \ +	andn		REG2, 0x7, REG2; \ +	ldx		[REG1 + REG2], REG1; \  	brz,pn		REG1, FAIL_LABEL; \  	 sllx		VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \  	srlx		REG2, 64 - PAGE_SHIFT, REG2; \ -	sllx		REG1, 11, REG1; \ -	andn		REG2, 0x3, REG2; \ -	lduwa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ +	andn		REG2, 0x7, REG2; \ +	ldxa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \  	brz,pn		REG1, FAIL_LABEL; \  	 sllx		VADDR, 64 - PMD_SHIFT, REG2; \  	srlx		REG2, 64 - PAGE_SHIFT, REG2; \ -	sllx		REG1, 11, REG1; \  	andn		REG2, 0x7, REG2; \  	add		REG1, REG2, REG1; -	/* Do a user page table walk in MMU globals.  Leaves physical PTE -	 * pointer in REG1.  Jumps to FAIL_LABEL on early page table walk -	 * termination.  Physical base of page tables is in PHYS_PGD which -	 * will not be modified. +	/* PMD has been loaded into REG1, interpret the value, seeing +	 * if it is a HUGE PMD or a normal one.  If it is not valid +	 * then jump to FAIL_LABEL.  If it is a HUGE PMD, and it +	 * translates to a valid PTE, branch to PTE_LABEL. +	 * +	 * We have to propagate the 4MB bit of the virtual address +	 * because we are fabricating 8MB pages using 4MB hw pages. +	 */ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \ +	brz,pn		REG1, FAIL_LABEL;		\ +	 sethi		%uhi(_PAGE_PMD_HUGE), REG2;	\ +	sllx		REG2, 32, REG2;			\ +	andcc		REG1, REG2, %g0;		\ +	be,pt		%xcc, 700f;			\ +	 sethi		%hi(4 * 1024 * 1024), REG2;	\ +	brgez,pn	REG1, FAIL_LABEL;		\ +	 andn		REG1, REG2, REG1;		\ +	and		VADDR, REG2, REG2;		\ +	brlz,pt		REG1, PTE_LABEL;		\ +	 or		REG1, REG2, REG1;		\ +700: +#else +#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \ +	brz,pn		REG1, FAIL_LABEL; \ +	 nop; +#endif + +	/* Do a user page table walk in MMU globals.  Leaves final, +	 * valid, PTE value in REG1.  Jumps to FAIL_LABEL on early +	 * page table walk termination or if the PTE is not valid. +	 * +	 * Physical base of page tables is in PHYS_PGD which will not +	 * be modified.  	 *  	 * VADDR will not be clobbered, but REG1 and REG2 will.  	 */  #define USER_PGTABLE_WALK_TL1(VADDR, PHYS_PGD, REG1, REG2, FAIL_LABEL)	\  	sllx		VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \  	srlx		REG2, 64 - PAGE_SHIFT, REG2; \ -	andn		REG2, 0x3, REG2; \ -	lduwa		[PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \ +	andn		REG2, 0x7, REG2; \ +	ldxa		[PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \  	brz,pn		REG1, FAIL_LABEL; \  	 sllx		VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \  	srlx		REG2, 64 - PAGE_SHIFT, REG2; \ -	sllx		REG1, 11, REG1; \ -	andn		REG2, 0x3, REG2; \ -	lduwa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ -	brz,pn		REG1, FAIL_LABEL; \ -	 sllx		VADDR, 64 - PMD_SHIFT, REG2; \ +	andn		REG2, 0x7, REG2; \ +	ldxa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ +	USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, 800f) \ +	sllx		VADDR, 64 - PMD_SHIFT, REG2; \  	srlx		REG2, 64 - PAGE_SHIFT, REG2; \ -	sllx		REG1, 11, REG1; \  	andn		REG2, 0x7, REG2; \ -	add		REG1, REG2, REG1; +	add		REG1, REG2, REG1; \ +	ldxa		[REG1] ASI_PHYS_USE_EC, REG1; \ +	brgez,pn	REG1, FAIL_LABEL; \ +	 nop; \ +800:  /* Lookup a OBP mapping on VADDR in the prom_trans[] table at TL>0.   * If no entry is found, FAIL_LABEL will be branched to.  On success @@ -239,6 +246,8 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;  	(KERNEL_TSB_SIZE_BYTES / 16)  #define KERNEL_TSB4M_NENTRIES	4096 +#define KTSB_PHYS_SHIFT		15 +  	/* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL  	 * on TSB hit.  REG1, REG2, REG3, and REG4 are used as temporaries  	 * and the found TTE will be left in REG1.  REG3 and REG4 must @@ -247,13 +256,22 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;  	 * VADDR and TAG will be preserved and not clobbered by this macro.  	 */  #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ -	sethi		%hi(swapper_tsb), REG1; \ +661:	sethi		%hi(swapper_tsb), REG1;			\  	or		REG1, %lo(swapper_tsb), REG1; \ +	.section	.swapper_tsb_phys_patch, "ax"; \ +	.word		661b; \ +	.previous; \ +661:	nop; \ +	.section	.tsb_ldquad_phys_patch, "ax"; \ +	.word		661b; \ +	sllx		REG1, KTSB_PHYS_SHIFT, REG1; \ +	sllx		REG1, KTSB_PHYS_SHIFT, REG1; \ +	.previous; \  	srlx		VADDR, PAGE_SHIFT, REG2; \  	and		REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \  	sllx		REG2, 4, REG2; \  	add		REG1, REG2, REG2; \ -	KTSB_LOAD_QUAD(REG2, REG3); \ +	TSB_LOAD_QUAD(REG2, REG3); \  	cmp		REG3, TAG; \  	be,a,pt		%xcc, OK_LABEL; \  	 mov		REG4, REG1; @@ -263,12 +281,21 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;  	 * we can make use of that for the index computation.  	 */  #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ -	sethi		%hi(swapper_4m_tsb), REG1; \ +661:	sethi		%hi(swapper_4m_tsb), REG1;	     \  	or		REG1, %lo(swapper_4m_tsb), REG1; \ +	.section	.swapper_4m_tsb_phys_patch, "ax"; \ +	.word		661b; \ +	.previous; \ +661:	nop; \ +	.section	.tsb_ldquad_phys_patch, "ax"; \ +	.word		661b; \ +	sllx		REG1, KTSB_PHYS_SHIFT, REG1; \ +	sllx		REG1, KTSB_PHYS_SHIFT, REG1; \ +	.previous; \  	and		TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \  	sllx		REG2, 4, REG2; \  	add		REG1, REG2, REG2; \ -	KTSB_LOAD_QUAD(REG2, REG3); \ +	TSB_LOAD_QUAD(REG2, REG3); \  	cmp		REG3, TAG; \  	be,a,pt		%xcc, OK_LABEL; \  	 mov		REG4, REG1;  | 
