tsb.S 4.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/* tsb.S: Sparc64 TSB table handling.
 *
 * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
 */

#include <asm/tsb.h>

	.text
	.align	32

	/* Invoked from TLB miss handler, we are in the
	 * MMU global registers and they are setup like
	 * this:
	 *
	 * %g1: TSB entry pointer
	 * %g2:	available temporary
	 * %g3:	FAULT_CODE_{D,I}TLB
	 * %g4:	available temporary
	 * %g5:	available temporary
	 * %g6: TAG TARGET
	 * %g7:	physical address base of the linux page
	 *      tables for the current address space
	 */
	.globl		tsb_miss_dtlb
tsb_miss_dtlb:
	mov		TLB_TAG_ACCESS, %g4
	ldxa		[%g4] ASI_DMMU, %g4
	ba,pt		%xcc, tsb_miss_page_table_walk
	 nop

	.globl		tsb_miss_itlb
tsb_miss_itlb:
	mov		TLB_TAG_ACCESS, %g4
	ldxa		[%g4] ASI_IMMU, %g4
	ba,pt		%xcc, tsb_miss_page_table_walk
	 nop

tsb_miss_page_table_walk:
39 40 41 42 43 44 45 46 47
	/* This clobbers %g1 and %g6, preserve them... */
	mov		%g1, %g5
	mov		%g6, %g2

	TRAP_LOAD_PGD_PHYS

	mov		%g2, %g6
	mov		%g5, %g1

48 49 50 51 52 53 54 55 56 57
	USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault)

tsb_reload:
	TSB_LOCK_TAG(%g1, %g2, %g4)

	/* Load and check PTE.  */
	ldxa		[%g5] ASI_PHYS_USE_EC, %g5
	brgez,a,pn	%g5, tsb_do_fault
	 stx		%g0, [%g1]

D
David S. Miller 已提交
58 59 60 61 62 63 64 65 66 67 68
	/* If it is larger than the base page size, don't
	 * bother putting it into the TSB.
	 */
	srlx		%g5, 32, %g2
	sethi		%hi(_PAGE_ALL_SZ_BITS >> 32), %g4
	sethi		%hi(_PAGE_SZBITS >> 32), %g7
	and		%g2, %g4, %g2
	cmp		%g2, %g7
	bne,a,pn	%xcc, tsb_tlb_reload
	 stx		%g0, [%g1]

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	TSB_WRITE(%g1, %g5, %g6)

	/* Finally, load TLB and return from trap.  */
tsb_tlb_reload:
	cmp		%g3, FAULT_CODE_DTLB
	bne,pn		%xcc, tsb_itlb_load
	 nop

tsb_dtlb_load:
	stxa		%g5, [%g0] ASI_DTLB_DATA_IN
	retry

tsb_itlb_load:
	stxa		%g5, [%g0] ASI_ITLB_DATA_IN
	retry

	/* No valid entry in the page tables, do full fault
	 * processing.
	 */

	.globl		tsb_do_fault
tsb_do_fault:
	cmp		%g3, FAULT_CODE_DTLB
	rdpr		%pstate, %g5
	bne,pn		%xcc, tsb_do_itlb_fault
	 wrpr		%g5, PSTATE_AG | PSTATE_MG, %pstate

tsb_do_dtlb_fault:
	rdpr	%tl, %g4
	cmp	%g4, 1
	mov	TLB_TAG_ACCESS, %g4
	ldxa	[%g4] ASI_DMMU, %g5
	be,pt	%xcc, sparc64_realfault_common
	 mov	FAULT_CODE_DTLB, %g4
	ba,pt	%xcc, winfix_trampoline
	 nop

tsb_do_itlb_fault:
	rdpr	%tpc, %g5
	ba,pt	%xcc, sparc64_realfault_common
	 mov	FAULT_CODE_ITLB, %g4

	.globl	sparc64_realfault_common
sparc64_realfault_common:
	stb	%g4, [%g6 + TI_FAULT_CODE]	! Save fault code
	stx	%g5, [%g6 + TI_FAULT_ADDR]	! Save fault address
	ba,pt	%xcc, etrap			! Save trap state
1:	 rd	%pc, %g7			! ...
	call	do_sparc64_fault		! Call fault handler
	 add	%sp, PTREGS_OFF, %o0		! Compute pt_regs arg
	ba,pt	%xcc, rtrap_clr_l6		! Restore cpu state
	 nop					! Delay slot (fill me)

	.globl	winfix_trampoline
winfix_trampoline:
	rdpr	%tpc, %g3			! Prepare winfixup TNPC
	or	%g3, 0x7c, %g3			! Compute branch offset
	wrpr	%g3, %tnpc			! Write it into TNPC
	done					! Trap return

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	/* Insert an entry into the TSB.
	 *
	 * %o0: TSB entry pointer
	 * %o1: tag
	 * %o2:	pte
	 */
	.align	32
	.globl	tsb_insert
tsb_insert:
	rdpr	%pstate, %o5
	wrpr	%o5, PSTATE_IE, %pstate
	TSB_LOCK_TAG(%o0, %g2, %g3)
	TSB_WRITE(%o0, %o2, %o1)
	wrpr	%o5, %pstate
	retl
	 nop

146 147 148 149
	/* Reload MMU related context switch state at
	 * schedule() time.
	 *
	 * %o0: page table physical address
150 151 152 153 154 155 156
	 * %o1:	TSB register value
	 * %o2:	TSB virtual address
	 * %o3:	TSB mapping locked PTE
	 *
	 * We have to run this whole thing with interrupts
	 * disabled so that the current cpu doesn't change
	 * due to preemption.
157
	 */
158
	.align	32
159 160
	.globl	__tsb_context_switch
__tsb_context_switch:
161 162
	rdpr	%pstate, %o5
	wrpr	%o5, PSTATE_IE, %pstate
163

164 165 166 167 168 169
	ldub	[%g6 + TI_CPU], %g1
	sethi	%hi(trap_block), %g2
	sllx	%g1, TRAP_BLOCK_SZ_SHIFT, %g1
	or	%g2, %lo(trap_block), %g2
	add	%g2, %g1, %g2
	stx	%o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
170 171

	mov	TSB_REG, %g1
172
	stxa	%o1, [%g1] ASI_DMMU
173 174
	membar	#Sync

175
	stxa	%o1, [%g1] ASI_IMMU
176 177
	membar	#Sync

178 179
	brz	%o2, 9f
	 nop
180 181 182 183 184 185 186 187 188 189 190 191

	/* We use entry 61 for this locked entry.  This is the spitfire
	 * TLB entry number, and luckily cheetah masks the value with
	 * 15 ending us up with entry 13 which is what we want in that
	 * case too.
	 *
	 * XXX Interactions with prom_world()...
	 */
	mov		TLB_TAG_ACCESS, %g1
	stxa		%o2, [%g1] ASI_DMMU
	membar		#Sync
	mov		(61 << 3), %g1
192
	stxa		%o3, [%g1] ASI_DTLB_DATA_ACCESS
193 194
	membar		#Sync
9:
195
	wrpr	%o5, %pstate
196 197

	retl
198
	 nop