[SPARC64]: Fix incorrect TSB lock bit handling.
[linux-2.6.git] / include / asm-sparc64 / tsb.h
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_BIT        47
51 #define TSB_TAG_LOCK_HIGH       (1 << (TSB_TAG_LOCK_BIT - 32))
52
53 #define TSB_MEMBAR      membar  #StoreStore
54
55 #define TSB_LOCK_TAG(TSB, REG1, REG2)   \
56 99:     lduwa   [TSB] ASI_N, REG1;      \
57         sethi   %hi(TSB_TAG_LOCK_HIGH), REG2;\
58         andcc   REG1, REG2, %g0;        \
59         bne,pn  %icc, 99b;              \
60          nop;                           \
61         casa    [TSB] ASI_N, REG1, REG2;\
62         cmp     REG1, REG2;             \
63         bne,pn  %icc, 99b;              \
64          nop;                           \
65         TSB_MEMBAR
66
67 #define TSB_WRITE(TSB, TTE, TAG)           \
68         stx             TTE, [TSB + 0x08]; \
69         TSB_MEMBAR;                        \
70         stx             TAG, [TSB + 0x00];
71
72         /* Do a kernel page table walk.  Leaves physical PTE pointer in
73          * REG1.  Jumps to FAIL_LABEL on early page table walk termination.
74          * VADDR will not be clobbered, but REG2 will.
75          */
76 #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL)        \
77         sethi           %hi(swapper_pg_dir), REG1; \
78         or              REG1, %lo(swapper_pg_dir), REG1; \
79         sllx            VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
80         srlx            REG2, 64 - PAGE_SHIFT, REG2; \
81         andn            REG2, 0x3, REG2; \
82         lduw            [REG1 + REG2], REG1; \
83         brz,pn          REG1, FAIL_LABEL; \
84          sllx           VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
85         srlx            REG2, 64 - PAGE_SHIFT, REG2; \
86         sllx            REG1, 11, REG1; \
87         andn            REG2, 0x3, REG2; \
88         lduwa           [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
89         brz,pn          REG1, FAIL_LABEL; \
90          sllx           VADDR, 64 - PMD_SHIFT, REG2; \
91         srlx            REG2, 64 - PAGE_SHIFT, REG2; \
92         sllx            REG1, 11, REG1; \
93         andn            REG2, 0x7, REG2; \
94         add             REG1, REG2, REG1;
95
96         /* Do a user page table walk in MMU globals.  Leaves physical PTE
97          * pointer in REG1.  Jumps to FAIL_LABEL on early page table walk
98          * termination.  Physical base of page tables is in PHYS_PGD which
99          * will not be modified.
100          *
101          * VADDR will not be clobbered, but REG1 and REG2 will.
102          */
103 #define USER_PGTABLE_WALK_TL1(VADDR, PHYS_PGD, REG1, REG2, FAIL_LABEL)  \
104         sllx            VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
105         srlx            REG2, 64 - PAGE_SHIFT, REG2; \
106         andn            REG2, 0x3, REG2; \
107         lduwa           [PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \
108         brz,pn          REG1, FAIL_LABEL; \
109          sllx           VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
110         srlx            REG2, 64 - PAGE_SHIFT, REG2; \
111         sllx            REG1, 11, REG1; \
112         andn            REG2, 0x3, REG2; \
113         lduwa           [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
114         brz,pn          REG1, FAIL_LABEL; \
115          sllx           VADDR, 64 - PMD_SHIFT, REG2; \
116         srlx            REG2, 64 - PAGE_SHIFT, REG2; \
117         sllx            REG1, 11, REG1; \
118         andn            REG2, 0x7, REG2; \
119         add             REG1, REG2, REG1;
120
121 /* Lookup a OBP mapping on VADDR in the prom_trans[] table at TL>0.
122  * If no entry is found, FAIL_LABEL will be branched to.  On success
123  * the resulting PTE value will be left in REG1.  VADDR is preserved
124  * by this routine.
125  */
126 #define OBP_TRANS_LOOKUP(VADDR, REG1, REG2, REG3, FAIL_LABEL) \
127         sethi           %hi(prom_trans), REG1; \
128         or              REG1, %lo(prom_trans), REG1; \
129 97:     ldx             [REG1 + 0x00], REG2; \
130         brz,pn          REG2, FAIL_LABEL; \
131          nop; \
132         ldx             [REG1 + 0x08], REG3; \
133         add             REG2, REG3, REG3; \
134         cmp             REG2, VADDR; \
135         bgu,pt          %xcc, 98f; \
136          cmp            VADDR, REG3; \
137         bgeu,pt         %xcc, 98f; \
138          ldx            [REG1 + 0x10], REG3; \
139         sub             VADDR, REG2, REG2; \
140         ba,pt           %xcc, 99f; \
141          add            REG3, REG2, REG1; \
142 98:     ba,pt           %xcc, 97b; \
143          add            REG1, (3 * 8), REG1; \
144 99:
145
146         /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
147          * on TSB hit.  REG1, REG2, REG3, and REG4 are used as temporaries
148          * and the found TTE will be left in REG1.  REG3 and REG4 must
149          * be an even/odd pair of registers.
150          *
151          * VADDR and TAG will be preserved and not clobbered by this macro.
152          */
153         /* XXX non-8K base page size support... */
154 #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
155         sethi           %hi(swapper_tsb), REG1; \
156         or              REG1, %lo(swapper_tsb), REG1; \
157         srlx            VADDR, 13, REG2; \
158         and             REG2, (512 - 1), REG2; \
159         sllx            REG2, 4, REG2; \
160         add             REG1, REG2, REG2; \
161         ldda            [REG2] ASI_NUCLEUS_QUAD_LDD, REG3; \
162         cmp             REG3, TAG; \
163         be,a,pt         %xcc, OK_LABEL; \
164          mov            REG4, REG1;
165
166 #endif /* !(_SPARC64_TSB_H) */