162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _SPARC64_TSB_H
362306a36Sopenharmony_ci#define _SPARC64_TSB_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/* The sparc64 TSB is similar to the powerpc hashtables.  It's a
662306a36Sopenharmony_ci * power-of-2 sized table of TAG/PTE pairs.  The cpu precomputes
762306a36Sopenharmony_ci * pointers into this table for 8K and 64K page sizes, and also a
862306a36Sopenharmony_ci * comparison TAG based upon the virtual address and context which
962306a36Sopenharmony_ci * faults.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * TLB miss trap handler software does the actual lookup via something
1262306a36Sopenharmony_ci * of the form:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * 	ldxa		[%g0] ASI_{D,I}MMU_TSB_8KB_PTR, %g1
1562306a36Sopenharmony_ci * 	ldxa		[%g0] ASI_{D,I}MMU, %g6
1662306a36Sopenharmony_ci *	sllx		%g6, 22, %g6
1762306a36Sopenharmony_ci *	srlx		%g6, 22, %g6
1862306a36Sopenharmony_ci * 	ldda		[%g1] ASI_NUCLEUS_QUAD_LDD, %g4
1962306a36Sopenharmony_ci * 	cmp		%g4, %g6
2062306a36Sopenharmony_ci * 	bne,pn	%xcc, tsb_miss_{d,i}tlb
2162306a36Sopenharmony_ci * 	 mov		FAULT_CODE_{D,I}TLB, %g3
2262306a36Sopenharmony_ci * 	stxa		%g5, [%g0] ASI_{D,I}TLB_DATA_IN
2362306a36Sopenharmony_ci * 	retry
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Each 16-byte slot of the TSB is the 8-byte tag and then the 8-byte
2762306a36Sopenharmony_ci * PTE.  The TAG is of the same layout as the TLB TAG TARGET mmu
2862306a36Sopenharmony_ci * register which is:
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * -------------------------------------------------
3162306a36Sopenharmony_ci * |  -  |  CONTEXT |  -  |    VADDR bits 63:22    |
3262306a36Sopenharmony_ci * -------------------------------------------------
3362306a36Sopenharmony_ci *  63 61 60      48 47 42 41                     0
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * But actually, since we use per-mm TSB's, we zero out the CONTEXT
3662306a36Sopenharmony_ci * field.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Like the powerpc hashtables we need to use locking in order to
3962306a36Sopenharmony_ci * synchronize while we update the entries.  PTE updates need locking
4062306a36Sopenharmony_ci * as well.
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * We need to carefully choose a lock bits for the TSB entry.  We
4362306a36Sopenharmony_ci * choose to use bit 47 in the tag.  Also, since we never map anything
4462306a36Sopenharmony_ci * at page zero in context zero, we use zero as an invalid tag entry.
4562306a36Sopenharmony_ci * When the lock bit is set, this forces a tag comparison failure.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define TSB_TAG_LOCK_BIT	47
4962306a36Sopenharmony_ci#define TSB_TAG_LOCK_HIGH	(1 << (TSB_TAG_LOCK_BIT - 32))
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define TSB_TAG_INVALID_BIT	46
5262306a36Sopenharmony_ci#define TSB_TAG_INVALID_HIGH	(1 << (TSB_TAG_INVALID_BIT - 32))
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* Some cpus support physical address quad loads.  We want to use
5562306a36Sopenharmony_ci * those if possible so we don't need to hard-lock the TSB mapping
5662306a36Sopenharmony_ci * into the TLB.  We encode some instruction patching in order to
5762306a36Sopenharmony_ci * support this.
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * The kernel TSB is locked into the TLB by virtue of being in the
6062306a36Sopenharmony_ci * kernel image, so we don't play these games for swapper_tsb access.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ci#ifndef __ASSEMBLY__
6362306a36Sopenharmony_cistruct tsb_ldquad_phys_patch_entry {
6462306a36Sopenharmony_ci	unsigned int	addr;
6562306a36Sopenharmony_ci	unsigned int	sun4u_insn;
6662306a36Sopenharmony_ci	unsigned int	sun4v_insn;
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ciextern struct tsb_ldquad_phys_patch_entry __tsb_ldquad_phys_patch,
6962306a36Sopenharmony_ci	__tsb_ldquad_phys_patch_end;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct tsb_phys_patch_entry {
7262306a36Sopenharmony_ci	unsigned int	addr;
7362306a36Sopenharmony_ci	unsigned int	insn;
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ciextern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
7662306a36Sopenharmony_ci#endif
7762306a36Sopenharmony_ci#define TSB_LOAD_QUAD(TSB, REG)	\
7862306a36Sopenharmony_ci661:	ldda		[TSB] ASI_NUCLEUS_QUAD_LDD, REG; \
7962306a36Sopenharmony_ci	.section	.tsb_ldquad_phys_patch, "ax"; \
8062306a36Sopenharmony_ci	.word		661b; \
8162306a36Sopenharmony_ci	ldda		[TSB] ASI_QUAD_LDD_PHYS, REG; \
8262306a36Sopenharmony_ci	ldda		[TSB] ASI_QUAD_LDD_PHYS_4V, REG; \
8362306a36Sopenharmony_ci	.previous
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define TSB_LOAD_TAG_HIGH(TSB, REG) \
8662306a36Sopenharmony_ci661:	lduwa		[TSB] ASI_N, REG; \
8762306a36Sopenharmony_ci	.section	.tsb_phys_patch, "ax"; \
8862306a36Sopenharmony_ci	.word		661b; \
8962306a36Sopenharmony_ci	lduwa		[TSB] ASI_PHYS_USE_EC, REG; \
9062306a36Sopenharmony_ci	.previous
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define TSB_LOAD_TAG(TSB, REG) \
9362306a36Sopenharmony_ci661:	ldxa		[TSB] ASI_N, REG; \
9462306a36Sopenharmony_ci	.section	.tsb_phys_patch, "ax"; \
9562306a36Sopenharmony_ci	.word		661b; \
9662306a36Sopenharmony_ci	ldxa		[TSB] ASI_PHYS_USE_EC, REG; \
9762306a36Sopenharmony_ci	.previous
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define TSB_CAS_TAG_HIGH(TSB, REG1, REG2) \
10062306a36Sopenharmony_ci661:	casa		[TSB] ASI_N, REG1, REG2; \
10162306a36Sopenharmony_ci	.section	.tsb_phys_patch, "ax"; \
10262306a36Sopenharmony_ci	.word		661b; \
10362306a36Sopenharmony_ci	casa		[TSB] ASI_PHYS_USE_EC, REG1, REG2; \
10462306a36Sopenharmony_ci	.previous
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define TSB_CAS_TAG(TSB, REG1, REG2) \
10762306a36Sopenharmony_ci661:	casxa		[TSB] ASI_N, REG1, REG2; \
10862306a36Sopenharmony_ci	.section	.tsb_phys_patch, "ax"; \
10962306a36Sopenharmony_ci	.word		661b; \
11062306a36Sopenharmony_ci	casxa		[TSB] ASI_PHYS_USE_EC, REG1, REG2; \
11162306a36Sopenharmony_ci	.previous
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define TSB_STORE(ADDR, VAL) \
11462306a36Sopenharmony_ci661:	stxa		VAL, [ADDR] ASI_N; \
11562306a36Sopenharmony_ci	.section	.tsb_phys_patch, "ax"; \
11662306a36Sopenharmony_ci	.word		661b; \
11762306a36Sopenharmony_ci	stxa		VAL, [ADDR] ASI_PHYS_USE_EC; \
11862306a36Sopenharmony_ci	.previous
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define TSB_LOCK_TAG(TSB, REG1, REG2)	\
12162306a36Sopenharmony_ci99:	TSB_LOAD_TAG_HIGH(TSB, REG1);	\
12262306a36Sopenharmony_ci	sethi	%hi(TSB_TAG_LOCK_HIGH), REG2;\
12362306a36Sopenharmony_ci	andcc	REG1, REG2, %g0;	\
12462306a36Sopenharmony_ci	bne,pn	%icc, 99b;		\
12562306a36Sopenharmony_ci	 nop;				\
12662306a36Sopenharmony_ci	TSB_CAS_TAG_HIGH(TSB, REG1, REG2);	\
12762306a36Sopenharmony_ci	cmp	REG1, REG2;		\
12862306a36Sopenharmony_ci	bne,pn	%icc, 99b;		\
12962306a36Sopenharmony_ci	 nop;				\
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci#define TSB_WRITE(TSB, TTE, TAG) \
13262306a36Sopenharmony_ci	add	TSB, 0x8, TSB;   \
13362306a36Sopenharmony_ci	TSB_STORE(TSB, TTE);     \
13462306a36Sopenharmony_ci	sub	TSB, 0x8, TSB;   \
13562306a36Sopenharmony_ci	TSB_STORE(TSB, TAG);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* Do a kernel page table walk.  Leaves valid PTE value in
13862306a36Sopenharmony_ci	 * REG1.  Jumps to FAIL_LABEL on early page table walk
13962306a36Sopenharmony_ci	 * termination.  VADDR will not be clobbered, but REG2 will.
14062306a36Sopenharmony_ci	 *
14162306a36Sopenharmony_ci	 * There are two masks we must apply to propagate bits from
14262306a36Sopenharmony_ci	 * the virtual address into the PTE physical address field
14362306a36Sopenharmony_ci	 * when dealing with huge pages.  This is because the page
14462306a36Sopenharmony_ci	 * table boundaries do not match the huge page size(s) the
14562306a36Sopenharmony_ci	 * hardware supports.
14662306a36Sopenharmony_ci	 *
14762306a36Sopenharmony_ci	 * In these cases we propagate the bits that are below the
14862306a36Sopenharmony_ci	 * page table level where we saw the huge page mapping, but
14962306a36Sopenharmony_ci	 * are still within the relevant physical bits for the huge
15062306a36Sopenharmony_ci	 * page size in question.  So for PMD mappings (which fall on
15162306a36Sopenharmony_ci	 * bit 23, for 8MB per PMD) we must propagate bit 22 for a
15262306a36Sopenharmony_ci	 * 4MB huge page.  For huge PUDs (which fall on bit 33, for
15362306a36Sopenharmony_ci	 * 8GB per PUD), we have to accommodate 256MB and 2GB huge
15462306a36Sopenharmony_ci	 * pages.  So for those we propagate bits 32 to 28.
15562306a36Sopenharmony_ci	 */
15662306a36Sopenharmony_ci#define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL)	\
15762306a36Sopenharmony_ci	sethi		%hi(swapper_pg_dir), REG1; \
15862306a36Sopenharmony_ci	or		REG1, %lo(swapper_pg_dir), REG1; \
15962306a36Sopenharmony_ci	sllx		VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
16062306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
16162306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
16262306a36Sopenharmony_ci	ldx		[REG1 + REG2], REG1; \
16362306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
16462306a36Sopenharmony_ci	 sllx		VADDR, 64 - (PUD_SHIFT + PUD_BITS), REG2; \
16562306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
16662306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
16762306a36Sopenharmony_ci	ldxa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
16862306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
16962306a36Sopenharmony_ci	sethi		%uhi(_PAGE_PUD_HUGE), REG2; \
17062306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
17162306a36Sopenharmony_ci	 sllx		REG2, 32, REG2; \
17262306a36Sopenharmony_ci	andcc		REG1, REG2, %g0; \
17362306a36Sopenharmony_ci	sethi		%hi(0xf8000000), REG2; \
17462306a36Sopenharmony_ci	bne,pt		%xcc, 697f; \
17562306a36Sopenharmony_ci	 sllx		REG2, 1, REG2; \
17662306a36Sopenharmony_ci	sllx		VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
17762306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
17862306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
17962306a36Sopenharmony_ci	ldxa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
18062306a36Sopenharmony_ci	sethi		%uhi(_PAGE_PMD_HUGE), REG2; \
18162306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
18262306a36Sopenharmony_ci	 sllx		REG2, 32, REG2; \
18362306a36Sopenharmony_ci	andcc		REG1, REG2, %g0; \
18462306a36Sopenharmony_ci	be,pn		%xcc, 698f; \
18562306a36Sopenharmony_ci	 sethi		%hi(0x400000), REG2; \
18662306a36Sopenharmony_ci697:	brgez,pn	REG1, FAIL_LABEL; \
18762306a36Sopenharmony_ci	 andn		REG1, REG2, REG1; \
18862306a36Sopenharmony_ci	and		VADDR, REG2, REG2; \
18962306a36Sopenharmony_ci	ba,pt		%xcc, 699f; \
19062306a36Sopenharmony_ci	 or		REG1, REG2, REG1; \
19162306a36Sopenharmony_ci698:	sllx		VADDR, 64 - PMD_SHIFT, REG2; \
19262306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
19362306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
19462306a36Sopenharmony_ci	ldxa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
19562306a36Sopenharmony_ci	brgez,pn	REG1, FAIL_LABEL; \
19662306a36Sopenharmony_ci	 nop; \
19762306a36Sopenharmony_ci699:
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* PUD has been loaded into REG1, interpret the value, seeing
20062306a36Sopenharmony_ci	 * if it is a HUGE PUD or a normal one.  If it is not valid
20162306a36Sopenharmony_ci	 * then jump to FAIL_LABEL.  If it is a HUGE PUD, and it
20262306a36Sopenharmony_ci	 * translates to a valid PTE, branch to PTE_LABEL.
20362306a36Sopenharmony_ci	 *
20462306a36Sopenharmony_ci	 * We have to propagate bits [32:22] from the virtual address
20562306a36Sopenharmony_ci	 * to resolve at 4M granularity.
20662306a36Sopenharmony_ci	 */
20762306a36Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
20862306a36Sopenharmony_ci#define USER_PGTABLE_CHECK_PUD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \
20962306a36Sopenharmony_ci700:	ba 700f;					\
21062306a36Sopenharmony_ci	 nop;						\
21162306a36Sopenharmony_ci	.section	.pud_huge_patch, "ax";		\
21262306a36Sopenharmony_ci	.word		700b;				\
21362306a36Sopenharmony_ci	nop;						\
21462306a36Sopenharmony_ci	.previous;					\
21562306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL;		\
21662306a36Sopenharmony_ci	 sethi		%uhi(_PAGE_PUD_HUGE), REG2;	\
21762306a36Sopenharmony_ci	sllx		REG2, 32, REG2;			\
21862306a36Sopenharmony_ci	andcc		REG1, REG2, %g0;		\
21962306a36Sopenharmony_ci	be,pt		%xcc, 700f;			\
22062306a36Sopenharmony_ci	 sethi		%hi(0xffe00000), REG2;		\
22162306a36Sopenharmony_ci	sllx		REG2, 1, REG2;			\
22262306a36Sopenharmony_ci	brgez,pn	REG1, FAIL_LABEL;		\
22362306a36Sopenharmony_ci	 andn		REG1, REG2, REG1;		\
22462306a36Sopenharmony_ci	and		VADDR, REG2, REG2;		\
22562306a36Sopenharmony_ci	brlz,pt		REG1, PTE_LABEL;		\
22662306a36Sopenharmony_ci	 or		REG1, REG2, REG1;		\
22762306a36Sopenharmony_ci700:
22862306a36Sopenharmony_ci#else
22962306a36Sopenharmony_ci#define USER_PGTABLE_CHECK_PUD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \
23062306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
23162306a36Sopenharmony_ci	 nop;
23262306a36Sopenharmony_ci#endif
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* PMD has been loaded into REG1, interpret the value, seeing
23562306a36Sopenharmony_ci	 * if it is a HUGE PMD or a normal one.  If it is not valid
23662306a36Sopenharmony_ci	 * then jump to FAIL_LABEL.  If it is a HUGE PMD, and it
23762306a36Sopenharmony_ci	 * translates to a valid PTE, branch to PTE_LABEL.
23862306a36Sopenharmony_ci	 *
23962306a36Sopenharmony_ci	 * We have to propagate the 4MB bit of the virtual address
24062306a36Sopenharmony_ci	 * because we are fabricating 8MB pages using 4MB hw pages.
24162306a36Sopenharmony_ci	 */
24262306a36Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
24362306a36Sopenharmony_ci#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \
24462306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL;		\
24562306a36Sopenharmony_ci	 sethi		%uhi(_PAGE_PMD_HUGE), REG2;	\
24662306a36Sopenharmony_ci	sllx		REG2, 32, REG2;			\
24762306a36Sopenharmony_ci	andcc		REG1, REG2, %g0;		\
24862306a36Sopenharmony_ci	be,pt		%xcc, 700f;			\
24962306a36Sopenharmony_ci	 sethi		%hi(4 * 1024 * 1024), REG2;	\
25062306a36Sopenharmony_ci	brgez,pn	REG1, FAIL_LABEL;		\
25162306a36Sopenharmony_ci	 andn		REG1, REG2, REG1;		\
25262306a36Sopenharmony_ci	and		VADDR, REG2, REG2;		\
25362306a36Sopenharmony_ci	brlz,pt		REG1, PTE_LABEL;		\
25462306a36Sopenharmony_ci	 or		REG1, REG2, REG1;		\
25562306a36Sopenharmony_ci700:
25662306a36Sopenharmony_ci#else
25762306a36Sopenharmony_ci#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \
25862306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
25962306a36Sopenharmony_ci	 nop;
26062306a36Sopenharmony_ci#endif
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Do a user page table walk in MMU globals.  Leaves final,
26362306a36Sopenharmony_ci	 * valid, PTE value in REG1.  Jumps to FAIL_LABEL on early
26462306a36Sopenharmony_ci	 * page table walk termination or if the PTE is not valid.
26562306a36Sopenharmony_ci	 *
26662306a36Sopenharmony_ci	 * Physical base of page tables is in PHYS_PGD which will not
26762306a36Sopenharmony_ci	 * be modified.
26862306a36Sopenharmony_ci	 *
26962306a36Sopenharmony_ci	 * VADDR will not be clobbered, but REG1 and REG2 will.
27062306a36Sopenharmony_ci	 */
27162306a36Sopenharmony_ci#define USER_PGTABLE_WALK_TL1(VADDR, PHYS_PGD, REG1, REG2, FAIL_LABEL)	\
27262306a36Sopenharmony_ci	sllx		VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
27362306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
27462306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
27562306a36Sopenharmony_ci	ldxa		[PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \
27662306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
27762306a36Sopenharmony_ci	 sllx		VADDR, 64 - (PUD_SHIFT + PUD_BITS), REG2; \
27862306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
27962306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
28062306a36Sopenharmony_ci	ldxa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
28162306a36Sopenharmony_ci	USER_PGTABLE_CHECK_PUD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, 800f) \
28262306a36Sopenharmony_ci	brz,pn		REG1, FAIL_LABEL; \
28362306a36Sopenharmony_ci	 sllx		VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
28462306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
28562306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
28662306a36Sopenharmony_ci	ldxa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
28762306a36Sopenharmony_ci	USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, 800f) \
28862306a36Sopenharmony_ci	sllx		VADDR, 64 - PMD_SHIFT, REG2; \
28962306a36Sopenharmony_ci	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
29062306a36Sopenharmony_ci	andn		REG2, 0x7, REG2; \
29162306a36Sopenharmony_ci	add		REG1, REG2, REG1; \
29262306a36Sopenharmony_ci	ldxa		[REG1] ASI_PHYS_USE_EC, REG1; \
29362306a36Sopenharmony_ci	brgez,pn	REG1, FAIL_LABEL; \
29462306a36Sopenharmony_ci	 nop; \
29562306a36Sopenharmony_ci800:
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/* Lookup a OBP mapping on VADDR in the prom_trans[] table at TL>0.
29862306a36Sopenharmony_ci * If no entry is found, FAIL_LABEL will be branched to.  On success
29962306a36Sopenharmony_ci * the resulting PTE value will be left in REG1.  VADDR is preserved
30062306a36Sopenharmony_ci * by this routine.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_ci#define OBP_TRANS_LOOKUP(VADDR, REG1, REG2, REG3, FAIL_LABEL) \
30362306a36Sopenharmony_ci	sethi		%hi(prom_trans), REG1; \
30462306a36Sopenharmony_ci	or		REG1, %lo(prom_trans), REG1; \
30562306a36Sopenharmony_ci97:	ldx		[REG1 + 0x00], REG2; \
30662306a36Sopenharmony_ci	brz,pn		REG2, FAIL_LABEL; \
30762306a36Sopenharmony_ci	 nop; \
30862306a36Sopenharmony_ci	ldx		[REG1 + 0x08], REG3; \
30962306a36Sopenharmony_ci	add		REG2, REG3, REG3; \
31062306a36Sopenharmony_ci	cmp		REG2, VADDR; \
31162306a36Sopenharmony_ci	bgu,pt		%xcc, 98f; \
31262306a36Sopenharmony_ci	 cmp		VADDR, REG3; \
31362306a36Sopenharmony_ci	bgeu,pt		%xcc, 98f; \
31462306a36Sopenharmony_ci	 ldx		[REG1 + 0x10], REG3; \
31562306a36Sopenharmony_ci	sub		VADDR, REG2, REG2; \
31662306a36Sopenharmony_ci	ba,pt		%xcc, 99f; \
31762306a36Sopenharmony_ci	 add		REG3, REG2, REG1; \
31862306a36Sopenharmony_ci98:	ba,pt		%xcc, 97b; \
31962306a36Sopenharmony_ci	 add		REG1, (3 * 8), REG1; \
32062306a36Sopenharmony_ci99:
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* We use a 32K TSB for the whole kernel, this allows to
32362306a36Sopenharmony_ci	 * handle about 16MB of modules and vmalloc mappings without
32462306a36Sopenharmony_ci	 * incurring many hash conflicts.
32562306a36Sopenharmony_ci	 */
32662306a36Sopenharmony_ci#define KERNEL_TSB_SIZE_BYTES	(32 * 1024)
32762306a36Sopenharmony_ci#define KERNEL_TSB_NENTRIES	\
32862306a36Sopenharmony_ci	(KERNEL_TSB_SIZE_BYTES / 16)
32962306a36Sopenharmony_ci#define KERNEL_TSB4M_NENTRIES	4096
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
33262306a36Sopenharmony_ci	 * on TSB hit.  REG1, REG2, REG3, and REG4 are used as temporaries
33362306a36Sopenharmony_ci	 * and the found TTE will be left in REG1.  REG3 and REG4 must
33462306a36Sopenharmony_ci	 * be an even/odd pair of registers.
33562306a36Sopenharmony_ci	 *
33662306a36Sopenharmony_ci	 * VADDR and TAG will be preserved and not clobbered by this macro.
33762306a36Sopenharmony_ci	 */
33862306a36Sopenharmony_ci#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
33962306a36Sopenharmony_ci661:	sethi		%uhi(swapper_tsb), REG1; \
34062306a36Sopenharmony_ci	sethi		%hi(swapper_tsb), REG2; \
34162306a36Sopenharmony_ci	or		REG1, %ulo(swapper_tsb), REG1; \
34262306a36Sopenharmony_ci	or		REG2, %lo(swapper_tsb), REG2; \
34362306a36Sopenharmony_ci	.section	.swapper_tsb_phys_patch, "ax"; \
34462306a36Sopenharmony_ci	.word		661b; \
34562306a36Sopenharmony_ci	.previous; \
34662306a36Sopenharmony_ci	sllx		REG1, 32, REG1; \
34762306a36Sopenharmony_ci	or		REG1, REG2, REG1; \
34862306a36Sopenharmony_ci	srlx		VADDR, PAGE_SHIFT, REG2; \
34962306a36Sopenharmony_ci	and		REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
35062306a36Sopenharmony_ci	sllx		REG2, 4, REG2; \
35162306a36Sopenharmony_ci	add		REG1, REG2, REG2; \
35262306a36Sopenharmony_ci	TSB_LOAD_QUAD(REG2, REG3); \
35362306a36Sopenharmony_ci	cmp		REG3, TAG; \
35462306a36Sopenharmony_ci	be,a,pt		%xcc, OK_LABEL; \
35562306a36Sopenharmony_ci	 mov		REG4, REG1;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci#ifndef CONFIG_DEBUG_PAGEALLOC
35862306a36Sopenharmony_ci	/* This version uses a trick, the TAG is already (VADDR >> 22) so
35962306a36Sopenharmony_ci	 * we can make use of that for the index computation.
36062306a36Sopenharmony_ci	 */
36162306a36Sopenharmony_ci#define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
36262306a36Sopenharmony_ci661:	sethi		%uhi(swapper_4m_tsb), REG1; \
36362306a36Sopenharmony_ci	sethi		%hi(swapper_4m_tsb), REG2; \
36462306a36Sopenharmony_ci	or		REG1, %ulo(swapper_4m_tsb), REG1; \
36562306a36Sopenharmony_ci	or		REG2, %lo(swapper_4m_tsb), REG2; \
36662306a36Sopenharmony_ci	.section	.swapper_4m_tsb_phys_patch, "ax"; \
36762306a36Sopenharmony_ci	.word		661b; \
36862306a36Sopenharmony_ci	.previous; \
36962306a36Sopenharmony_ci	sllx		REG1, 32, REG1; \
37062306a36Sopenharmony_ci	or		REG1, REG2, REG1; \
37162306a36Sopenharmony_ci	and		TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
37262306a36Sopenharmony_ci	sllx		REG2, 4, REG2; \
37362306a36Sopenharmony_ci	add		REG1, REG2, REG2; \
37462306a36Sopenharmony_ci	TSB_LOAD_QUAD(REG2, REG3); \
37562306a36Sopenharmony_ci	cmp		REG3, TAG; \
37662306a36Sopenharmony_ci	be,a,pt		%xcc, OK_LABEL; \
37762306a36Sopenharmony_ci	 mov		REG4, REG1;
37862306a36Sopenharmony_ci#endif
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci#endif /* !(_SPARC64_TSB_H) */
381