1f93b7d8cdbc023b000aa21e71fe44deb6d995c9
[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    (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) */