Merge branch 'master'
[linux-2.6] / arch / sparc64 / kernel / dtlb_backend.S
1 /* $Id: dtlb_backend.S,v 1.16 2001/10/09 04:02:11 davem Exp $
2  * dtlb_backend.S: Back end to DTLB miss replacement strategy.
3  *                 This is included directly into the trap table.
4  *
5  * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
6  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
7  */
8
9 #include <asm/pgtable.h>
10 #include <asm/mmu.h>
11
12 #define VALID_SZ_BITS   (_PAGE_VALID | _PAGE_SZBITS)
13
14 #define VPTE_BITS               (_PAGE_CP | _PAGE_CV | _PAGE_P )
15 #define VPTE_SHIFT              (PAGE_SHIFT - 3)
16
17 /* Ways we can get here:
18  *
19  * 1) Nucleus loads and stores to/from PA-->VA direct mappings at tl>1.
20  * 2) Nucleus loads and stores to/from user/kernel window save areas.
21  * 3) VPTE misses from dtlb_base and itlb_base.
22  *
23  * We need to extract out the PMD and PGDIR indexes from the
24  * linear virtual page table access address.  The PTE index
25  * is at the bottom, but we are not concerned with it.  Bits
26  * 0 to 2 are clear since each PTE is 8 bytes in size.  Each
27  * PMD and PGDIR entry are 4 bytes in size.   Thus, this
28  * address looks something like:
29  *
30  * |---------------------------------------------------------------|
31  * |  ...   |    PGDIR index    |    PMD index    | PTE index  |   |
32  * |---------------------------------------------------------------|
33  *   63   F   E               D   C             B   A         3 2 0  <- bit nr
34  *
35  *  The variable bits above are defined as:
36  *  A --> 3 + (PAGE_SHIFT - log2(8))
37  *    --> 3 + (PAGE_SHIFT - 3) - 1
38  *        (ie. this is "bit 3" + PAGE_SIZE - size of PTE entry in bits - 1)
39  *  B --> A + 1
40  *  C --> B + (PAGE_SHIFT - log2(4))
41  *    -->  B + (PAGE_SHIFT - 2) - 1
42  *        (ie. this is "bit B" + PAGE_SIZE - size of PMD entry in bits - 1)
43  *  D --> C + 1
44  *  E --> D + (PAGE_SHIFT - log2(4))
45  *    --> D + (PAGE_SHIFT - 2) - 1
46  *        (ie. this is "bit D" + PAGE_SIZE - size of PGDIR entry in bits - 1)
47  *  F --> E + 1
48  *
49  * (Note how "B" always evalutes to PAGE_SHIFT, all the other constants
50  *  cancel out.)
51  *
52  * For 8K PAGE_SIZE (thus, PAGE_SHIFT of 13) the bit numbers are:
53  * A --> 12
54  * B --> 13
55  * C --> 23
56  * D --> 24
57  * E --> 34
58  * F --> 35
59  *
60  * For 64K PAGE_SIZE (thus, PAGE_SHIFT of 16) the bit numbers are:
61  * A --> 15
62  * B --> 16
63  * C --> 29
64  * D --> 30
65  * E --> 43
66  * F --> 44
67  *
68  * Because bits both above and below each PGDIR and PMD index need to
69  * be masked out, and the index can be as long as 14 bits (when using a
70  * 64K PAGE_SIZE, and thus a PAGE_SHIFT of 16), we need 3 instructions
71  * to extract each index out.
72  *
73  * Shifts do not pair very well on UltraSPARC-I, II, IIi, and IIe, so
74  * we try to avoid using them for the entire operation.  We could setup
75  * a mask anywhere from bit 31 down to bit 10 using the sethi instruction.
76  *
77  * We need a mask covering bits B --> C and one covering D --> E.
78  * For 8K PAGE_SIZE these masks are 0x00ffe000 and 0x7ff000000.
79  * For 64K PAGE_SIZE these masks are 0x3fff0000 and 0xfffc0000000.
80  * The second in each set cannot be loaded with a single sethi
81  * instruction, because the upper bits are past bit 32.  We would
82  * need to use a sethi + a shift.
83  *
84  * For the time being, we use 2 shifts and a simple "and" mask.
85  * We shift left to clear the bits above the index, we shift down
86  * to clear the bits below the index (sans the log2(4 or 8) bits)
87  * and a mask to clear the log2(4 or 8) bits.  We need therefore
88  * define 4 shift counts, all of which are relative to PAGE_SHIFT.
89  *
90  * Although unsupportable for other reasons, this does mean that
91  * 512K and 4MB page sizes would be generaally supported by the
92  * kernel.  (ELF binaries would break with > 64K PAGE_SIZE since
93  * the sections are only aligned that strongly).
94  *
95  * The operations performed for extraction are thus:
96  *
97  *      ((X << FOO_SHIFT_LEFT) >> FOO_SHIFT_RIGHT) & ~0x3
98  *
99  */
100
101 #define A (3 + (PAGE_SHIFT - 3) - 1)
102 #define B (A + 1)
103 #define C (B + (PAGE_SHIFT - 2) - 1)
104 #define D (C + 1)
105 #define E (D + (PAGE_SHIFT - 2) - 1)
106 #define F (E + 1)
107
108 #define PMD_SHIFT_LEFT          (64 - D)
109 #define PMD_SHIFT_RIGHT         (64 - (D - B) - 2)
110 #define PGDIR_SHIFT_LEFT        (64 - F)
111 #define PGDIR_SHIFT_RIGHT       (64 - (F - D) - 2)
112 #define LOW_MASK_BITS           0x3
113
114 /* TLB1 ** ICACHE line 1: tl1 DTLB and quick VPTE miss  */
115         ldxa            [%g1 + %g1] ASI_DMMU, %g4       ! Get TAG_ACCESS
116         add             %g3, %g3, %g5                   ! Compute VPTE base
117         cmp             %g4, %g5                        ! VPTE miss?
118         bgeu,pt         %xcc, 1f                        ! Continue here
119          andcc          %g4, TAG_CONTEXT_BITS, %g5      ! tl0 miss Nucleus test
120         ba,a,pt         %xcc, from_tl1_trap             ! Fall to tl0 miss
121 1:      sllx            %g6, VPTE_SHIFT, %g4            ! Position TAG_ACCESS
122         or              %g4, %g5, %g4                   ! Prepare TAG_ACCESS
123
124 /* TLB1 ** ICACHE line 2: Quick VPTE miss               */
125         mov             TSB_REG, %g1                    ! Grab TSB reg
126         ldxa            [%g1] ASI_DMMU, %g5             ! Doing PGD caching?
127         sllx            %g6, PMD_SHIFT_LEFT, %g1        ! Position PMD offset
128         be,pn           %xcc, sparc64_vpte_nucleus      ! Is it from Nucleus?
129          srlx           %g1, PMD_SHIFT_RIGHT, %g1       ! Mask PMD offset bits
130         brnz,pt         %g5, sparc64_vpte_continue      ! Yep, go like smoke
131          andn           %g1, LOW_MASK_BITS, %g1         ! Final PMD mask
132         sllx            %g6, PGDIR_SHIFT_LEFT, %g5      ! Position PGD offset
133
134 /* TLB1 ** ICACHE line 3: Quick VPTE miss               */
135         srlx            %g5, PGDIR_SHIFT_RIGHT, %g5     ! Mask PGD offset bits
136         andn            %g5, LOW_MASK_BITS, %g5         ! Final PGD mask
137         lduwa           [%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
138         brz,pn          %g5, vpte_noent                 ! Valid?
139 sparc64_kpte_continue:
140          sllx           %g5, 11, %g5                    ! Shift into place
141 sparc64_vpte_continue:
142         lduwa           [%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD
143         sllx            %g5, 11, %g5                    ! Shift into place
144         brz,pn          %g5, vpte_noent                 ! Valid?
145
146 /* TLB1 ** ICACHE line 4: Quick VPTE miss               */
147          mov            (VALID_SZ_BITS >> 61), %g1      ! upper vpte into %g1
148         sllx            %g1, 61, %g1                    ! finish calc
149         or              %g5, VPTE_BITS, %g5             ! Prepare VPTE data
150         or              %g5, %g1, %g5                   ! ...
151         mov             TLB_SFSR, %g1                   ! Restore %g1 value
152         stxa            %g5, [%g0] ASI_DTLB_DATA_IN     ! Load VPTE into TLB
153         stxa            %g4, [%g1 + %g1] ASI_DMMU       ! Restore previous TAG_ACCESS
154         retry                                           ! Load PTE once again
155
156 #undef VALID_SZ_BITS
157 #undef VPTE_SHIFT
158 #undef VPTE_BITS
159 #undef A
160 #undef B
161 #undef C
162 #undef D
163 #undef E
164 #undef F
165 #undef PMD_SHIFT_LEFT
166 #undef PMD_SHIFT_RIGHT
167 #undef PGDIR_SHIFT_LEFT
168 #undef PGDIR_SHIFT_RIGHT
169 #undef LOW_MASK_BITS
170