diff options
Diffstat (limited to 'include/asm-sparc64/tsb.h')
-rw-r--r-- | include/asm-sparc64/tsb.h | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/include/asm-sparc64/tsb.h b/include/asm-sparc64/tsb.h new file mode 100644 index 000000000000..03d272e0e477 --- /dev/null +++ b/include/asm-sparc64/tsb.h | |||
@@ -0,0 +1,165 @@ | |||
1 | #ifndef _SPARC64_TSB_H | ||
2 | #define _SPARC64_TSB_H | ||
3 | |||
4 | /* The sparc64 TSB is similar to the powerpc hashtables. It's a | ||
5 | * power-of-2 sized table of TAG/PTE pairs. The cpu precomputes | ||
6 | * pointers into this table for 8K and 64K page sizes, and also a | ||
7 | * comparison TAG based upon the virtual address and context which | ||
8 | * faults. | ||
9 | * | ||
10 | * TLB miss trap handler software does the actual lookup via something | ||
11 | * of the form: | ||
12 | * | ||
13 | * ldxa [%g0] ASI_{D,I}MMU_TSB_8KB_PTR, %g1 | ||
14 | * ldxa [%g0] ASI_{D,I}MMU, %g6 | ||
15 | * ldda [%g1] ASI_NUCLEUS_QUAD_LDD, %g4 | ||
16 | * cmp %g4, %g6 | ||
17 | * bne,pn %xcc, tsb_miss_{d,i}tlb | ||
18 | * mov FAULT_CODE_{D,I}TLB, %g3 | ||
19 | * stxa %g5, [%g0] ASI_{D,I}TLB_DATA_IN | ||
20 | * retry | ||
21 | * | ||
22 | |||
23 | * Each 16-byte slot of the TSB is the 8-byte tag and then the 8-byte | ||
24 | * PTE. The TAG is of the same layout as the TLB TAG TARGET mmu | ||
25 | * register which is: | ||
26 | * | ||
27 | * ------------------------------------------------- | ||
28 | * | - | CONTEXT | - | VADDR bits 63:22 | | ||
29 | * ------------------------------------------------- | ||
30 | * 63 61 60 48 47 42 41 0 | ||
31 | * | ||
32 | * Like the powerpc hashtables we need to use locking in order to | ||
33 | * synchronize while we update the entries. PTE updates need locking | ||
34 | * as well. | ||
35 | * | ||
36 | * We need to carefully choose a lock bits for the TSB entry. We | ||
37 | * choose to use bit 47 in the tag. Also, since we never map anything | ||
38 | * at page zero in context zero, we use zero as an invalid tag entry. | ||
39 | * When the lock bit is set, this forces a tag comparison failure. | ||
40 | * | ||
41 | * Currently, we allocate an 8K TSB per-process and we use it for both | ||
42 | * I-TLB and D-TLB misses. Perhaps at some point we'll add code that | ||
43 | * monitors the number of active pages in the process as we get | ||
44 | * major/minor faults, and grow the TSB in response. The only trick | ||
45 | * in implementing that is synchronizing the freeing of the old TSB | ||
46 | * wrt. parallel TSB updates occuring on other processors. On | ||
47 | * possible solution is to use RCU for the freeing of the TSB. | ||
48 | */ | ||
49 | |||
50 | #define TSB_TAG_LOCK (1 << (47 - 32)) | ||
51 | |||
52 | #define TSB_MEMBAR membar #StoreStore | ||
53 | |||
54 | #define TSB_LOCK_TAG(TSB, REG1, REG2) \ | ||
55 | 99: lduwa [TSB] ASI_N, REG1; \ | ||
56 | sethi %hi(TSB_TAG_LOCK), REG2;\ | ||
57 | andcc REG1, REG2, %g0; \ | ||
58 | bne,pn %icc, 99b; \ | ||
59 | nop; \ | ||
60 | casa [TSB] ASI_N, REG1, REG2;\ | ||
61 | cmp REG1, REG2; \ | ||
62 | bne,pn %icc, 99b; \ | ||
63 | nop; \ | ||
64 | TSB_MEMBAR | ||
65 | |||
66 | #define TSB_WRITE(TSB, TTE, TAG) \ | ||
67 | stx TTE, [TSB + 0x08]; \ | ||
68 | TSB_MEMBAR; \ | ||
69 | stx TAG, [TSB + 0x00]; | ||
70 | |||
71 | /* Do a kernel page table walk. Leaves physical PTE pointer in | ||
72 | * REG1. Jumps to FAIL_LABEL on early page table walk termination. | ||
73 | * VADDR will not be clobbered, but REG2 will. | ||
74 | */ | ||
75 | #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL) \ | ||
76 | sethi %hi(swapper_pg_dir), REG1; \ | ||
77 | or REG1, %lo(swapper_pg_dir), REG1; \ | ||
78 | sllx VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \ | ||
79 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
80 | andn REG2, 0x3, REG2; \ | ||
81 | lduw [REG1 + REG2], REG1; \ | ||
82 | brz,pn REG1, FAIL_LABEL; \ | ||
83 | sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ | ||
84 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
85 | sllx REG1, 11, REG1; \ | ||
86 | andn REG2, 0x3, REG2; \ | ||
87 | lduwa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ | ||
88 | brz,pn REG1, FAIL_LABEL; \ | ||
89 | sllx VADDR, 64 - PMD_SHIFT, REG2; \ | ||
90 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
91 | sllx REG1, 11, REG1; \ | ||
92 | andn REG2, 0x7, REG2; \ | ||
93 | add REG1, REG2, REG1; | ||
94 | |||
95 | /* Do a user page table walk in MMU globals. Leaves physical PTE | ||
96 | * pointer in REG1. Jumps to FAIL_LABEL on early page table walk | ||
97 | * termination. Physical base of page tables is in PHYS_PGD which | ||
98 | * will not be modified. | ||
99 | * | ||
100 | * VADDR will not be clobbered, but REG1 and REG2 will. | ||
101 | */ | ||
102 | #define USER_PGTABLE_WALK_TL1(VADDR, PHYS_PGD, REG1, REG2, FAIL_LABEL) \ | ||
103 | sllx VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \ | ||
104 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
105 | andn REG2, 0x3, REG2; \ | ||
106 | lduwa [PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \ | ||
107 | brz,pn REG1, FAIL_LABEL; \ | ||
108 | sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ | ||
109 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
110 | sllx REG1, 11, REG1; \ | ||
111 | andn REG2, 0x3, REG2; \ | ||
112 | lduwa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ | ||
113 | brz,pn REG1, FAIL_LABEL; \ | ||
114 | sllx VADDR, 64 - PMD_SHIFT, REG2; \ | ||
115 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
116 | sllx REG1, 11, REG1; \ | ||
117 | andn REG2, 0x7, REG2; \ | ||
118 | add REG1, REG2, REG1; | ||
119 | |||
120 | /* Lookup a OBP mapping on VADDR in the prom_trans[] table at TL>0. | ||
121 | * If no entry is found, FAIL_LABEL will be branched to. On success | ||
122 | * the resulting PTE value will be left in REG1. VADDR is preserved | ||
123 | * by this routine. | ||
124 | */ | ||
125 | #define OBP_TRANS_LOOKUP(VADDR, REG1, REG2, REG3, FAIL_LABEL) \ | ||
126 | sethi %hi(prom_trans), REG1; \ | ||
127 | or REG1, %lo(prom_trans), REG1; \ | ||
128 | 97: ldx [REG1 + 0x00], REG2; \ | ||
129 | brz,pn REG2, FAIL_LABEL; \ | ||
130 | nop; \ | ||
131 | ldx [REG1 + 0x08], REG3; \ | ||
132 | add REG2, REG3, REG3; \ | ||
133 | cmp REG2, VADDR; \ | ||
134 | bgu,pt %xcc, 98f; \ | ||
135 | cmp VADDR, REG3; \ | ||
136 | bgeu,pt %xcc, 98f; \ | ||
137 | ldx [REG1 + 0x10], REG3; \ | ||
138 | sub VADDR, REG2, REG2; \ | ||
139 | ba,pt %xcc, 99f; \ | ||
140 | add REG3, REG2, REG1; \ | ||
141 | 98: ba,pt %xcc, 97b; \ | ||
142 | add REG1, (3 * 8), REG1; \ | ||
143 | 99: | ||
144 | |||
145 | /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL | ||
146 | * on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries | ||
147 | * and the found TTE will be left in REG1. REG3 and REG4 must | ||
148 | * be an even/odd pair of registers. | ||
149 | * | ||
150 | * VADDR and TAG will be preserved and not clobbered by this macro. | ||
151 | */ | ||
152 | /* XXX non-8K base page size support... */ | ||
153 | #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ | ||
154 | sethi %hi(swapper_tsb), REG1; \ | ||
155 | or REG1, %lo(swapper_tsb), REG1; \ | ||
156 | srlx VADDR, 13, REG2; \ | ||
157 | and REG2, (512 - 1), REG2; \ | ||
158 | sllx REG2, 4, REG2; \ | ||
159 | add REG1, REG2, REG2; \ | ||
160 | ldda [REG2] ASI_NUCLEUS_QUAD_LDD, REG3; \ | ||
161 | cmp REG3, TAG; \ | ||
162 | be,a,pt %xcc, OK_LABEL; \ | ||
163 | mov REG4, REG1; | ||
164 | |||
165 | #endif /* !(_SPARC64_TSB_H) */ | ||