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

Commit fe11dc3f authored by Joakim Tjernlund's avatar Joakim Tjernlund Committed by Benjamin Herrenschmidt
Browse files

powerpc/8xx: Update TLB asm so it behaves as linux mm expects.



Update the TLB asm to make proper use of _PAGE_DIRY and _PAGE_ACCESSED.
Get rid of _PAGE_HWWRITE too.
Pros:
 - I/D TLB Miss never needs to write to the linux pte.
 - _PAGE_ACCESSED is only set on TLB Error fixing accounting
 - _PAGE_DIRTY is mapped to 0x100, the changed bit, and is set directly
    when a page has been made dirty.
 - Proper RO/RW mapping of user space.
 - Free up 2 SW TLB bits in the linux pte(add back _PAGE_WRITETHRU ?)
 - kernel RO/user NA support.
Cons:
 - A few more instructions in the TLB Miss routines.

Signed-off-by: default avatarJoakim Tjernlund <Joakim.Tjernlund@transmode.se>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 5efab4a0
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -33,21 +33,20 @@
#define _PAGE_NO_CACHE	0x0002	/* I: cache inhibit */
#define _PAGE_SHARED	0x0004	/* No ASID (context) compare */
#define _PAGE_SPECIAL	0x0008	/* SW entry, forced to 0 by the TLB miss */
#define _PAGE_DIRTY	0x0100	/* C: page changed */

/* These five software bits must be masked out when the entry is loaded
 * into the TLB.
/* These 3 software bits must be masked out when the entry is loaded
 * into the TLB, 2 SW bits left.
 */
#define _PAGE_GUARDED	0x0010	/* software: guarded access */
#define _PAGE_DIRTY	0x0020	/* software: page changed */
#define _PAGE_RW	0x0040	/* software: user write access allowed */
#define _PAGE_ACCESSED	0x0080	/* software: page referenced */
#define _PAGE_ACCESSED	0x0020	/* software: page referenced */

/* Setting any bits in the nibble with the follow two controls will
 * require a TLB exception handler change.  It is assumed unused bits
 * are always zero.
 */
#define _PAGE_HWWRITE	0x0100	/* h/w write enable: never set in Linux PTE */
#define _PAGE_USER	0x0800	/* One of the PP bits, the other is USER&~RW */
#define _PAGE_RW	0x0400	/* lsb PP bits, inverted in HW */
#define _PAGE_USER	0x0800	/* msb PP bits */

#define _PMD_PRESENT	0x0001
#define _PMD_BAD	0x0ff0
+51 −48
Original line number Diff line number Diff line
@@ -333,26 +333,20 @@ InstructionTLBMiss:
	mfspr	r11, SPRN_MD_TWC	/* ....and get the pte address */
	lwz	r10, 0(r11)	/* Get the pte */

#ifdef CONFIG_SWAP
	/* do not set the _PAGE_ACCESSED bit of a non-present page */
	andi.	r11, r10, _PAGE_PRESENT
	beq	4f
	ori	r10, r10, _PAGE_ACCESSED
	mfspr	r11, SPRN_MD_TWC	/* get the pte address again */
	stw	r10, 0(r11)
4:
#else
	ori	r10, r10, _PAGE_ACCESSED
	stw	r10, 0(r11)
#endif
	andi.	r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT
	cmpwi	cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT
	bne-	cr0, 2f

	/* Clear PP lsb, 0x400 */
	rlwinm 	r10, r10, 0, 22, 20

	/* The Linux PTE won't go exactly into the MMU TLB.
	 * Software indicator bits 21, 22 and 28 must be clear.
	 * Software indicator bits 22 and 28 must be clear.
	 * Software indicator bits 24, 25, 26, and 27 must be
	 * set.  All other Linux PTE bits control the behavior
	 * of the MMU.
	 */
2:	li	r11, 0x00f0
	li	r11, 0x00f0
	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */
	DO_8xx_CPU6(0x2d80, r3)
	mtspr	SPRN_MI_RPN, r10	/* Update TLB entry */
@@ -365,6 +359,22 @@ InstructionTLBMiss:
	lwz	r3, 8(r0)
#endif
	rfi
2:
	mfspr	r11, SPRN_SRR1
	/* clear all error bits as TLB Miss
	 * sets a few unconditionally
	*/
	rlwinm	r11, r11, 0, 0xffff
	mtspr	SPRN_SRR1, r11

	mfspr	r10, SPRN_M_TW	/* Restore registers */
	lwz	r11, 0(r0)
	mtcr	r11
	lwz	r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
	lwz	r3, 8(r0)
#endif
	b	InstructionAccess

	. = 0x1200
DataStoreTLBMiss:
@@ -409,21 +419,27 @@ DataStoreTLBMiss:
	DO_8xx_CPU6(0x3b80, r3)
	mtspr	SPRN_MD_TWC, r11

#ifdef CONFIG_SWAP
	/* do not set the _PAGE_ACCESSED bit of a non-present page */
	andi.	r11, r10, _PAGE_PRESENT
	beq	4f
	ori	r10, r10, _PAGE_ACCESSED
4:
	/* and update pte in table */
#else
	ori	r10, r10, _PAGE_ACCESSED
#endif
	mfspr	r11, SPRN_MD_TWC	/* get the pte address again */
	stw	r10, 0(r11)
	/* Both _PAGE_ACCESSED and _PAGE_PRESENT has to be set.
	 * We also need to know if the insn is a load/store, so:
	 * Clear _PAGE_PRESENT and load that which will
	 * trap into DTLB Error with store bit set accordinly.
	 */
	/* PRESENT=0x1, ACCESSED=0x20
	 * r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5));
	 * r10 = (r10 & ~PRESENT) | r11;
	 */
	rlwinm	r11, r10, 32-5, 31, 31
	and	r11, r11, r10
	rlwimi	r10, r11, 0, 31, 31

	/* Honour kernel RO, User NA */
	andi.	r11, r10, _PAGE_USER | _PAGE_RW
	bne-	cr0, 5f
	ori	r10,r10, 0x200 /* Extended encoding, bit 22 */
5:	xori	r10, r10, _PAGE_RW  /* invert RW bit */

	/* The Linux PTE won't go exactly into the MMU TLB.
	 * Software indicator bits 21, 22 and 28 must be clear.
	 * Software indicator bits 22 and 28 must be clear.
	 * Software indicator bits 24, 25, 26, and 27 must be
	 * set.  All other Linux PTE bits control the behavior
	 * of the MMU.
@@ -469,11 +485,12 @@ DataTLBError:
	stw	r10, 0(r0)
	stw	r11, 4(r0)

	/* First, make sure this was a store operation.
	mfspr	r11, SPRN_DSISR
	andis.	r11, r11, 0x4800	/* !translation or protection */
	bne	2f	/* branch if either is set */
	/* Only Change bit left now, do it here as it is faster
	 * than trapping to the C fault handler.
	*/
	mfspr	r10, SPRN_DSISR
	andis.	r11, r10, 0x0200	/* If set, indicates store op */
	beq	2f

	/* The EA of a data TLB miss is automatically stored in the MD_EPN
	 * register.  The EA of a data TLB error is automatically stored in
@@ -522,26 +539,12 @@ DataTLBError:
	mfspr	r11, SPRN_MD_TWC		/* ....and get the pte address */
	lwz	r10, 0(r11)		/* Get the pte */

	andi.	r11, r10, _PAGE_RW	/* Is it writeable? */
	beq	2f			/* Bail out if not */

	/* Update 'changed', among others.
	*/
#ifdef CONFIG_SWAP
	ori	r10, r10, _PAGE_DIRTY|_PAGE_HWWRITE
	/* do not set the _PAGE_ACCESSED bit of a non-present page */
	andi.	r11, r10, _PAGE_PRESENT
	beq	4f
	ori	r10, r10, _PAGE_ACCESSED
4:
#else
	ori	r10, r10, _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HWWRITE
#endif
	mfspr	r11, SPRN_MD_TWC		/* Get pte address again */
	stw	r10, 0(r11)		/* and update pte in table */
	xori	r10, r10, _PAGE_RW	/* RW bit is inverted */

	/* The Linux PTE won't go exactly into the MMU TLB.
	 * Software indicator bits 21, 22 and 28 must be clear.
	 * Software indicator bits 22 and 28 must be clear.
	 * Software indicator bits 24, 25, 26, and 27 must be
	 * set.  All other Linux PTE bits control the behavior
	 * of the MMU.