v2.4.10.4 -> v2.4.10.5
[opensuse:kernel.git] / include / asm-sparc64 / processor.h
1 /* $Id: processor.h,v 1.75 2001/09/20 00:35:34 davem Exp $
2  * include/asm-sparc64/processor.h
3  *
4  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
5  */
6
7 #ifndef __ASM_SPARC64_PROCESSOR_H
8 #define __ASM_SPARC64_PROCESSOR_H
9
10 /*
11  * Sparc64 implementation of macro that returns current
12  * instruction pointer ("program counter").
13  */
14 #define current_text_addr() ({ void *pc; __asm__("rd %%pc, %0" : "=r" (pc)); pc; })
15
16 #include <linux/config.h>
17 #include <asm/asi.h>
18 #include <asm/a.out.h>
19 #include <asm/pstate.h>
20 #include <asm/ptrace.h>
21 #include <asm/signal.h>
22 #include <asm/segment.h>
23 #include <asm/page.h>
24
25 /* Bus types */
26 #define EISA_bus 0
27 #define EISA_bus__is_a_macro /* for versions in ksyms.c */
28 #define MCA_bus 0
29 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
30
31 /* The sparc has no problems with write protection */
32 #define wp_works_ok 1
33 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
34
35 /*
36  * User lives in his very own context, and cannot reference us. Note
37  * that TASK_SIZE is a misnomer, it really gives maximum user virtual 
38  * address that the kernel will allocate out.
39  */
40 #define VA_BITS         44
41 #define VPTE_SIZE       (1UL << (VA_BITS - PAGE_SHIFT + 3))
42 #define TASK_SIZE       ((unsigned long)-VPTE_SIZE)
43
44 #ifndef __ASSEMBLY__
45
46 #define NSWINS          7
47
48 typedef struct {
49         unsigned char seg;
50 } mm_segment_t;
51
52 /* The Sparc processor specific thread struct. */
53 struct thread_struct {
54         /* D$ line 1 */
55         unsigned long ksp __attribute__ ((aligned(16)));
56         unsigned char wstate, cwp, flags;
57         mm_segment_t current_ds;
58         unsigned char w_saved, fpdepth, fault_code, use_blkcommit;
59         unsigned long fault_address;
60         unsigned char fpsaved[7];
61         unsigned char __pad2;
62         
63         /* D$ line 2, 3, 4 */
64         struct pt_regs *kregs;
65         unsigned long *utraps;
66         unsigned long gsr[7];
67         unsigned long xfsr[7];
68
69         struct reg_window reg_window[NSWINS];
70         unsigned long rwbuf_stkptrs[NSWINS];
71         
72         /* Performance counter state */
73         u64 *user_cntd0, *user_cntd1;
74         u64 kernel_cntd0, kernel_cntd1;
75         u64 pcr_reg;
76 };
77
78 #endif /* !(__ASSEMBLY__) */
79
80 #define SPARC_FLAG_UNALIGNED    0x01    /* is allowed to do unaligned accesses  */
81 #define SPARC_FLAG_NEWSIGNALS   0x02    /* task wants new-style signals         */
82 #define SPARC_FLAG_32BIT        0x04    /* task is older 32-bit binary          */
83 #define SPARC_FLAG_NEWCHILD     0x08    /* task is just-spawned child process   */
84 #define SPARC_FLAG_PERFCTR      0x10    /* task has performance counters active */
85
86 #define FAULT_CODE_WRITE        0x01    /* Write access, implies D-TLB          */
87 #define FAULT_CODE_DTLB         0x02    /* Miss happened in D-TLB               */
88 #define FAULT_CODE_ITLB         0x04    /* Miss happened in I-TLB               */
89 #define FAULT_CODE_WINFIXUP     0x08    /* Miss happened during spill/fill      */
90
91 #define INIT_THREAD  {                                  \
92 /* ksp, wstate, cwp, flags, current_ds, */              \
93    0,   0,      0,   0,     KERNEL_DS,                  \
94 /* w_saved, fpdepth, fault_code, use_blkcommit, */      \
95    0,       0,       0,          0,                     \
96 /* fault_address, fpsaved, __pad2, kregs, */            \
97    0,             { 0 },   0,      0,                   \
98 /* utraps, gsr,   xfsr, */                              \
99    0,      { 0 }, { 0 },                                \
100 /* reg_window */                                        \
101    { { { 0, }, { 0, } }, },                             \
102 /* rwbuf_stkptrs */                                     \
103    { 0, 0, 0, 0, 0, 0, 0, },                            \
104 /* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
105    0,          0,          0,            0,            0, \
106 }
107
108 #ifdef __KERNEL__
109 #if PAGE_SHIFT == 13
110 #define THREAD_SIZE (2*PAGE_SIZE)
111 #define THREAD_SHIFT (PAGE_SHIFT + 1)
112 #else /* PAGE_SHIFT == 13 */
113 #define THREAD_SIZE PAGE_SIZE
114 #define THREAD_SHIFT PAGE_SHIFT
115 #endif /* PAGE_SHIFT == 13 */
116 #endif /* __KERNEL__ */
117
118 #ifndef __ASSEMBLY__
119
120 /* Return saved PC of a blocked thread. */
121 extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
122 {
123         unsigned long ret = 0xdeadbeefUL;
124         
125         if (t->ksp) {
126                 unsigned long *sp;
127                 sp = (unsigned long *)(t->ksp + STACK_BIAS);
128                 if (((unsigned long)sp & (sizeof(long) - 1)) == 0UL &&
129                     sp[14]) {
130                         unsigned long *fp;
131                         fp = (unsigned long *)(sp[14] + STACK_BIAS);
132                         if (((unsigned long)fp & (sizeof(long) - 1)) == 0UL)
133                                 ret = fp[15];
134                 }
135         }
136         return ret;
137 }
138
139 /* On Uniprocessor, even in RMO processes see TSO semantics */
140 #ifdef CONFIG_SMP
141 #define TSTATE_INITIAL_MM       TSTATE_TSO
142 #else
143 #define TSTATE_INITIAL_MM       TSTATE_RMO
144 #endif
145
146 /* Do necessary setup to start up a newly executed thread. */
147 #define start_thread(regs, pc, sp) \
148 do { \
149         regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (ASI_PNF << 24); \
150         regs->tpc = ((pc & (~3)) - 4); \
151         regs->tnpc = regs->tpc + 4; \
152         regs->y = 0; \
153         current->thread.wstate = (1 << 3); \
154         if (current->thread.utraps) { \
155                 if (*(current->thread.utraps) < 2) \
156                         kfree (current->thread.utraps); \
157                 else \
158                         (*(current->thread.utraps))--; \
159                 current->thread.utraps = NULL; \
160         } \
161         __asm__ __volatile__( \
162         "stx            %%g0, [%0 + %2 + 0x00]\n\t" \
163         "stx            %%g0, [%0 + %2 + 0x08]\n\t" \
164         "stx            %%g0, [%0 + %2 + 0x10]\n\t" \
165         "stx            %%g0, [%0 + %2 + 0x18]\n\t" \
166         "stx            %%g0, [%0 + %2 + 0x20]\n\t" \
167         "stx            %%g0, [%0 + %2 + 0x28]\n\t" \
168         "stx            %%g0, [%0 + %2 + 0x30]\n\t" \
169         "stx            %%g0, [%0 + %2 + 0x38]\n\t" \
170         "stx            %%g0, [%0 + %2 + 0x40]\n\t" \
171         "stx            %%g0, [%0 + %2 + 0x48]\n\t" \
172         "stx            %%g0, [%0 + %2 + 0x50]\n\t" \
173         "stx            %%g0, [%0 + %2 + 0x58]\n\t" \
174         "stx            %%g0, [%0 + %2 + 0x60]\n\t" \
175         "stx            %%g0, [%0 + %2 + 0x68]\n\t" \
176         "stx            %1,   [%0 + %2 + 0x70]\n\t" \
177         "stx            %%g0, [%0 + %2 + 0x78]\n\t" \
178         "wrpr           %%g0, (1 << 3), %%wstate\n\t" \
179         : \
180         : "r" (regs), "r" (sp - REGWIN_SZ - STACK_BIAS), \
181           "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
182 } while(0)
183
184 #define start_thread32(regs, pc, sp) \
185 do { \
186         pc &= 0x00000000ffffffffUL; \
187         sp &= 0x00000000ffffffffUL; \
188 \
189         regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM); \
190         regs->tpc = ((pc & (~3)) - 4); \
191         regs->tnpc = regs->tpc + 4; \
192         regs->y = 0; \
193         current->thread.wstate = (2 << 3); \
194         if (current->thread.utraps) { \
195                 if (*(current->thread.utraps) < 2) \
196                         kfree (current->thread.utraps); \
197                 else \
198                         (*(current->thread.utraps))--; \
199                 current->thread.utraps = NULL; \
200         } \
201         __asm__ __volatile__( \
202         "stx            %%g0, [%0 + %2 + 0x00]\n\t" \
203         "stx            %%g0, [%0 + %2 + 0x08]\n\t" \
204         "stx            %%g0, [%0 + %2 + 0x10]\n\t" \
205         "stx            %%g0, [%0 + %2 + 0x18]\n\t" \
206         "stx            %%g0, [%0 + %2 + 0x20]\n\t" \
207         "stx            %%g0, [%0 + %2 + 0x28]\n\t" \
208         "stx            %%g0, [%0 + %2 + 0x30]\n\t" \
209         "stx            %%g0, [%0 + %2 + 0x38]\n\t" \
210         "stx            %%g0, [%0 + %2 + 0x40]\n\t" \
211         "stx            %%g0, [%0 + %2 + 0x48]\n\t" \
212         "stx            %%g0, [%0 + %2 + 0x50]\n\t" \
213         "stx            %%g0, [%0 + %2 + 0x58]\n\t" \
214         "stx            %%g0, [%0 + %2 + 0x60]\n\t" \
215         "stx            %%g0, [%0 + %2 + 0x68]\n\t" \
216         "stx            %1,   [%0 + %2 + 0x70]\n\t" \
217         "stx            %%g0, [%0 + %2 + 0x78]\n\t" \
218         "wrpr           %%g0, (2 << 3), %%wstate\n\t" \
219         : \
220         : "r" (regs), "r" (sp - REGWIN32_SZ), \
221           "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
222 } while(0)
223
224 /* Free all resources held by a thread. */
225 #define release_thread(tsk)             do { } while(0)
226
227 extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
228
229 #define copy_segments(tsk, mm)          do { } while (0)
230 #define release_segments(mm)            do { } while (0)
231
232 #define get_wchan(__TSK) \
233 ({      extern void scheduling_functions_start_here(void); \
234         extern void scheduling_functions_end_here(void); \
235         unsigned long pc, fp, bias = 0; \
236         unsigned long task_base = (unsigned long) (__TSK); \
237         struct reg_window *rw; \
238         unsigned long __ret = 0; \
239         int count = 0; \
240         if (!(__TSK) || (__TSK) == current || \
241             (__TSK)->state == TASK_RUNNING) \
242                 goto __out; \
243         bias = STACK_BIAS; \
244         fp = (__TSK)->thread.ksp + bias; \
245         do { \
246                 /* Bogus frame pointer? */ \
247                 if (fp < (task_base + sizeof(struct task_struct)) || \
248                     fp >= (task_base + THREAD_SIZE)) \
249                         break; \
250                 rw = (struct reg_window *) fp; \
251                 pc = rw->ins[7]; \
252                 if (pc < ((unsigned long) scheduling_functions_start_here) || \
253                     pc >= ((unsigned long) scheduling_functions_end_here)) { \
254                         __ret = pc; \
255                         goto __out; \
256                 } \
257                 fp = rw->ins[6] + bias; \
258         } while (++count < 16); \
259 __out:  __ret; \
260 })
261
262 #define KSTK_EIP(tsk)  ((tsk)->thread.kregs->tpc)
263 #define KSTK_ESP(tsk)  ((tsk)->thread.kregs->u_regs[UREG_FP])
264
265 #ifdef __KERNEL__
266 /* Allocation and freeing of task_struct and kernel stack. */
267 #if PAGE_SHIFT == 13
268 #define alloc_task_struct()   ((struct task_struct *)__get_free_pages(GFP_KERNEL, 1))
269 #define free_task_struct(tsk) free_pages((unsigned long)(tsk),1)
270 #else /* PAGE_SHIFT == 13 */
271 #define alloc_task_struct()   ((struct task_struct *)__get_free_pages(GFP_KERNEL, 0))
272 #define free_task_struct(tsk) free_pages((unsigned long)(tsk),0)
273 #endif /* PAGE_SHIFT == 13 */
274 #define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
275
276 #define init_task       (init_task_union.task)
277 #define init_stack      (init_task_union.stack)
278
279 #define cpu_relax()     do { } while (0)
280
281 #endif /* __KERNEL__ */
282
283 #endif /* !(__ASSEMBLY__) */
284
285 #endif /* !(__ASM_SPARC64_PROCESSOR_H) */