Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74fabcad authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman
Browse files

powerpc/8xx: don't use r12/SPRN_SPRG_SCRATCH2 in TLB Miss handlers



This patch reworks the TLB Miss handler in order to not use r12
register, hence avoiding having to save it into SPRN_SPRG_SCRATCH2.

In the DAR Fixup code we can now use SPRN_M_TW, freeing
SPRN_SPRG_SCRATCH2.

Then SPRN_SPRG_SCRATCH2 may be used for something else in the future.

Signed-off-by: default avatarChristophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 55c8fc3f
Loading
Loading
Loading
Loading
+49 −61
Original line number Diff line number Diff line
@@ -302,90 +302,87 @@ SystemCall:
 */

#ifdef CONFIG_8xx_CPU15
#define INVALIDATE_ADJACENT_PAGES_CPU15(tmp, addr)	\
	addi	tmp, addr, PAGE_SIZE;	\
	tlbie	tmp;			\
	addi	tmp, addr, -PAGE_SIZE;	\
	tlbie	tmp
#define INVALIDATE_ADJACENT_PAGES_CPU15(addr)	\
	addi	addr, addr, PAGE_SIZE;	\
	tlbie	addr;			\
	addi	addr, addr, -(PAGE_SIZE << 1);	\
	tlbie	addr;			\
	addi	addr, addr, PAGE_SIZE
#else
#define INVALIDATE_ADJACENT_PAGES_CPU15(tmp, addr)
#define INVALIDATE_ADJACENT_PAGES_CPU15(addr)
#endif

InstructionTLBMiss:
	mtspr	SPRN_SPRG_SCRATCH0, r10
#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP)
	mtspr	SPRN_SPRG_SCRATCH1, r11
#ifdef ITLB_MISS_KERNEL
	mtspr	SPRN_SPRG_SCRATCH2, r12
#endif

	/* If we are faulting a kernel address, we have to use the
	 * kernel page tables.
	 */
	mfspr	r10, SPRN_SRR0	/* Get effective address of fault */
	INVALIDATE_ADJACENT_PAGES_CPU15(r11, r10)
	INVALIDATE_ADJACENT_PAGES_CPU15(r10)
	mtspr	SPRN_MD_EPN, r10
	/* Only modules will cause ITLB Misses as we always
	 * pin the first 8MB of kernel memory */
#ifdef ITLB_MISS_KERNEL
	mfcr	r12
	mfcr	r11
#if defined(SIMPLE_KERNEL_ADDRESS) && defined(CONFIG_PIN_TLB_TEXT)
	andis.	r11, r10, 0x8000	/* Address >= 0x80000000 */
	cmpi	cr0, r10, 0	/* Address >= 0x80000000 */
#else
	rlwinm	r11, r10, 16, 0xfff8
	cmpli	cr0, r11, PAGE_OFFSET@h
	rlwinm	r10, r10, 16, 0xfff8
	cmpli	cr0, r10, PAGE_OFFSET@h
#ifndef CONFIG_PIN_TLB_TEXT
	/* It is assumed that kernel code fits into the first 8M page */
0:	cmpli	cr7, r11, (PAGE_OFFSET + 0x0800000)@h
0:	cmpli	cr7, r10, (PAGE_OFFSET + 0x0800000)@h
	patch_site	0b, patch__itlbmiss_linmem_top
#endif
#endif
#endif
	mfspr	r11, SPRN_M_TWB	/* Get level 1 table */
	mfspr	r10, SPRN_M_TWB	/* Get level 1 table */
#ifdef ITLB_MISS_KERNEL
#if defined(SIMPLE_KERNEL_ADDRESS) && defined(CONFIG_PIN_TLB_TEXT)
	beq+	3f
	bge+	3f
#else
	blt+	3f
#endif
#ifndef CONFIG_PIN_TLB_TEXT
	blt	cr7, ITLBMissLinear
#endif
	rlwinm	r11, r11, 0, 20, 31
	oris	r11, r11, (swapper_pg_dir - PAGE_OFFSET)@ha
	rlwinm	r10, r10, 0, 20, 31
	oris	r10, r10, (swapper_pg_dir - PAGE_OFFSET)@ha
3:
#endif
	lwz	r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11)	/* Get the level 1 entry */
	lwz	r10, (swapper_pg_dir-PAGE_OFFSET)@l(r10)	/* Get level 1 entry */
	mtspr	SPRN_MI_TWC, r10	/* Set segment attributes */

	mtspr	SPRN_MD_TWC, r11
	mtspr	SPRN_MD_TWC, r10
	mfspr	r10, SPRN_MD_TWC
	lwz	r10, 0(r10)	/* Get the pte */
#ifdef ITLB_MISS_KERNEL
	mtcr	r12
	mtcr	r11
#endif
	/* Load the MI_TWC with the attributes for this "segment." */
	mtspr	SPRN_MI_TWC, r11	/* Set segment attributes */

#ifdef CONFIG_SWAP
	rlwinm	r11, r10, 32-5, _PAGE_PRESENT
	and	r11, r11, r10
	rlwimi	r10, r11, 0, _PAGE_PRESENT
#endif
	li	r11, RPN_PATTERN | 0x200
	/* The Linux PTE won't go exactly into the MMU TLB.
	 * Software indicator bits 20 and 23 must be clear.
	 * Software indicator bits 22, 24, 25, 26, and 27 must be
	 * set.  All other Linux PTE bits control the behavior
	 * of the MMU.
	 */
	rlwimi	r11, r10, 4, 0x0400	/* Copy _PAGE_EXEC into bit 21 */
	rlwimi	r10, r11, 0, 0x0ff0	/* Set 22, 24-27, clear 20,23 */
	rlwimi	r10, r10, 0, 0x0f00	/* Clear bits 20-23 */
	rlwimi	r10, r10, 4, 0x0400	/* Copy _PAGE_EXEC into bit 21 */
	ori	r10, r10, RPN_PATTERN | 0x200 /* Set 22 and 24-27 */
	mtspr	SPRN_MI_RPN, r10	/* Update TLB entry */

	/* Restore registers */
0:	mfspr	r10, SPRN_SPRG_SCRATCH0
#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP)
	mfspr	r11, SPRN_SPRG_SCRATCH1
#ifdef ITLB_MISS_KERNEL
	mfspr	r12, SPRN_SPRG_SCRATCH2
#endif
	rfi
	patch_site	0b, patch__itlbmiss_exit_1
@@ -396,9 +393,8 @@ InstructionTLBMiss:
	addi	r10, r10, 1
	stw	r10, (itlb_miss_counter - PAGE_OFFSET)@l(0)
	mfspr	r10, SPRN_SPRG_SCRATCH0
#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP)
	mfspr	r11, SPRN_SPRG_SCRATCH1
#ifdef ITLB_MISS_KERNEL
	mfspr	r12, SPRN_SPRG_SCRATCH2
#endif
	rfi
#endif
@@ -407,40 +403,37 @@ InstructionTLBMiss:
DataStoreTLBMiss:
	mtspr	SPRN_SPRG_SCRATCH0, r10
	mtspr	SPRN_SPRG_SCRATCH1, r11
	mtspr	SPRN_SPRG_SCRATCH2, r12
	mfcr	r12
	mfcr	r11

	/* If we are faulting a kernel address, we have to use the
	 * kernel page tables.
	 */
	mfspr	r10, SPRN_MD_EPN
	rlwinm	r11, r10, 16, 0xfff8
	cmpli	cr0, r11, PAGE_OFFSET@h
	mfspr	r11, SPRN_M_TWB	/* Get level 1 table */
	blt+	3f
	rlwinm	r11, r10, 16, 0xfff8
	rlwinm	r10, r10, 16, 0xfff8
	cmpli	cr0, r10, PAGE_OFFSET@h
#ifndef CONFIG_PIN_TLB_IMMR
	cmpli	cr0, r11, VIRT_IMMR_BASE@h
	cmpli	cr6, r10, VIRT_IMMR_BASE@h
#endif
0:	cmpli	cr7, r11, (PAGE_OFFSET + 0x1800000)@h
0:	cmpli	cr7, r10, (PAGE_OFFSET + 0x1800000)@h
	patch_site	0b, patch__dtlbmiss_linmem_top

	mfspr	r10, SPRN_M_TWB	/* Get level 1 table */
	blt+	3f
#ifndef CONFIG_PIN_TLB_IMMR
0:	beq-	DTLBMissIMMR
0:	beq-	cr6, DTLBMissIMMR
	patch_site	0b, patch__dtlbmiss_immr_jmp
#endif
	blt	cr7, DTLBMissLinear
	mfspr	r11, SPRN_M_TWB	/* Get level 1 table */
	rlwinm	r11, r11, 0, 20, 31
	oris	r11, r11, (swapper_pg_dir - PAGE_OFFSET)@ha
	rlwinm	r10, r10, 0, 20, 31
	oris	r10, r10, (swapper_pg_dir - PAGE_OFFSET)@ha
3:
	lwz	r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11)	/* Get the level 1 entry */
	mtcr	r11
	lwz	r11, (swapper_pg_dir-PAGE_OFFSET)@l(r10)	/* Get level 1 entry */

	mtspr	SPRN_MD_TWC, r11
	mfspr	r10, SPRN_MD_TWC
	lwz	r10, 0(r10)	/* Get the pte */

	mtcr	r12

	/* Insert the Guarded flag into the TWC from the Linux PTE.
	 * It is bit 27 of both the Linux PTE and the TWC (at least
	 * I got that right :-).  It will be better when we can put
@@ -478,7 +471,6 @@ DataStoreTLBMiss:

0:	mfspr	r10, SPRN_SPRG_SCRATCH0
	mfspr	r11, SPRN_SPRG_SCRATCH1
	mfspr	r12, SPRN_SPRG_SCRATCH2
	rfi
	patch_site	0b, patch__dtlbmiss_exit_1

@@ -489,7 +481,6 @@ DataStoreTLBMiss:
	stw	r10, (dtlb_miss_counter - PAGE_OFFSET)@l(0)
	mfspr	r10, SPRN_SPRG_SCRATCH0
	mfspr	r11, SPRN_SPRG_SCRATCH1
	mfspr	r12, SPRN_SPRG_SCRATCH2
	rfi
#endif

@@ -597,7 +588,7 @@ InstructionBreakpoint:
 * not enough space in the DataStoreTLBMiss area.
 */
DTLBMissIMMR:
	mtcr	r12
	mtcr	r11
	/* Set 512k byte guarded page and mark it valid */
	li	r10, MD_PS512K | MD_GUARDED | MD_SVALID
	mtspr	SPRN_MD_TWC, r10
@@ -612,16 +603,15 @@ DTLBMissIMMR:

0:	mfspr	r10, SPRN_SPRG_SCRATCH0
	mfspr	r11, SPRN_SPRG_SCRATCH1
	mfspr	r12, SPRN_SPRG_SCRATCH2
	rfi
	patch_site	0b, patch__dtlbmiss_exit_2

DTLBMissLinear:
	mtcr	r12
	mtcr	r11
	/* Set 8M byte page and mark it valid */
	li	r11, MD_PS8MEG | MD_SVALID
	mtspr	SPRN_MD_TWC, r11
	rlwinm	r10, r10, 0, 0x0f800000	/* 8xx supports max 256Mb RAM */
	rlwinm	r10, r10, 20, 0x0f800000	/* 8xx supports max 256Mb RAM */
	ori	r10, r10, 0xf0 | MD_SPS16K | _PAGE_SH | _PAGE_DIRTY | \
			  _PAGE_PRESENT
	mtspr	SPRN_MD_RPN, r10	/* Update TLB entry */
@@ -631,24 +621,22 @@ DTLBMissLinear:

0:	mfspr	r10, SPRN_SPRG_SCRATCH0
	mfspr	r11, SPRN_SPRG_SCRATCH1
	mfspr	r12, SPRN_SPRG_SCRATCH2
	rfi
	patch_site	0b, patch__dtlbmiss_exit_3

#ifndef CONFIG_PIN_TLB_TEXT
ITLBMissLinear:
	mtcr	r12
	mtcr	r11
	/* Set 8M byte page and mark it valid */
	li	r11, MI_PS8MEG | MI_SVALID
	mtspr	SPRN_MI_TWC, r11
	rlwinm	r10, r10, 0, 0x0f800000	/* 8xx supports max 256Mb RAM */
	rlwinm	r10, r10, 20, 0x0f800000	/* 8xx supports max 256Mb RAM */
	ori	r10, r10, 0xf0 | MI_SPS16K | _PAGE_SH | _PAGE_DIRTY | \
			  _PAGE_PRESENT
	mtspr	SPRN_MI_RPN, r10	/* Update TLB entry */

0:	mfspr	r10, SPRN_SPRG_SCRATCH0
	mfspr	r11, SPRN_SPRG_SCRATCH1
	mfspr	r12, SPRN_SPRG_SCRATCH2
	rfi
	patch_site	0b, patch__itlbmiss_exit_2
#endif
@@ -660,7 +648,7 @@ ITLBMissLinear:
 /* define if you don't want to use self modifying code */
#define NO_SELF_MODIFYING_CODE
FixupDAR:/* Entry point for dcbx workaround. */
	mtspr	SPRN_SPRG_SCRATCH2, r10
	mtspr	SPRN_M_TW, r10
	/* fetch instruction from memory. */
	mfspr	r10, SPRN_SRR0
	mtspr	SPRN_MD_EPN, r10
@@ -705,7 +693,7 @@ FixupDAR:/* Entry point for dcbx workaround. */
	beq+	142f
	cmpwi	cr0, r10, 1964	/* Is icbi? */
	beq+	142f
141:	mfspr	r10,SPRN_SPRG_SCRATCH2
141:	mfspr	r10,SPRN_M_TW
	b	DARFixed	/* Nope, go back to normal TLB processing */

200:
@@ -740,7 +728,7 @@ modified_instr:
	bne+	143f
	subf	r10,r0,r10	/* r10=r10-r0, only if reg RA is r0 */
143:	mtdar	r10		/* store faulting EA in DAR */
	mfspr	r10,SPRN_SPRG_SCRATCH2
	mfspr	r10,SPRN_M_TW
	b	DARFixed	/* Go back to normal TLB handling */
#else
	mfctr	r10
@@ -794,7 +782,7 @@ modified_instr:
	mfdar	r11
	mtctr	r11			/* restore ctr reg from DAR */
	mtdar	r10			/* save fault EA to DAR */
	mfspr	r10,SPRN_SPRG_SCRATCH2
	mfspr	r10,SPRN_M_TW
	b	DARFixed		/* Go back to normal TLB handling */

	/* special handling for r10,r11 since these are modified already */