import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / include / asm-parisc / processor.h
1 /*
2  * include/asm-parisc/processor.h
3  *
4  * Copyright (C) 1994 Linus Torvalds
5  * Copyright (C) 2001 Grant Grundler
6  */
7
8 #ifndef __ASM_PARISC_PROCESSOR_H
9 #define __ASM_PARISC_PROCESSOR_H
10
11 #ifndef __ASSEMBLY__
12 #include <linux/config.h>
13 #include <linux/threads.h>
14
15 #include <asm/hardware.h>
16 #include <asm/page.h>
17 #include <asm/pdc.h>
18 #include <asm/ptrace.h>
19 #include <asm/types.h>
20 #include <asm/system.h>
21 #ifdef CONFIG_SMP
22 #include <asm/spinlock_t.h>
23 #endif
24 #endif /* __ASSEMBLY__ */
25
26 /*
27  * Default implementation of macro that returns current
28  * instruction pointer ("program counter").
29  */
30
31 /* We cannot use MFIA as it was added for PA2.0 - prumpf
32
33    At one point there were no "0f/0b" type local symbols in gas for
34    PA-RISC.  This is no longer true, but this still seems like the
35    nicest way to implement this. */
36
37 #define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
38
39 #define TASK_SIZE               (current->thread.task_size)
40 #define DEFAULT_TASK_SIZE       (0xFFF00000UL)
41
42 #define TASK_UNMAPPED_BASE      (current->thread.map_base)
43 #define DEFAULT_MAP_BASE        (0x40000000UL)
44
45 #ifndef __ASSEMBLY__
46
47 /*
48 ** Data detected about CPUs at boot time which is the same for all CPU's.
49 ** HP boxes are SMP - ie identical processors.
50 **
51 ** FIXME: some CPU rev info may be processor specific...
52 */
53 struct system_cpuinfo_parisc {
54         unsigned int    cpu_count;
55         unsigned int    cpu_hz;
56         unsigned int    hversion;
57         unsigned int    sversion;
58         enum cpu_type   cpu_type;
59
60         struct {
61                 struct pdc_model model;
62                 unsigned long versions;
63                 unsigned long cpuid;
64                 unsigned long capabilities;
65                 char   sys_model_name[81]; /* PDC-ROM returnes this model name */
66         } pdc;
67
68         char            *cpu_name;      /* e.g. "PA7300LC (PCX-L2)" */
69         char            *family_name;   /* e.g. "1.1e" */
70 };
71
72
73 /*
74 ** Per CPU data structure - ie varies per CPU.
75 */
76 struct cpuinfo_parisc {
77
78         unsigned long it_value;     /* Interval Timer value at last timer Intr */
79         unsigned long it_delta;     /* Interval Timer delta (tic_10ms / HZ * 100) */
80         unsigned long irq_count;    /* number of IRQ's since boot */
81         unsigned long irq_max_cr16; /* longest time to handle a single IRQ */
82         unsigned long cpuid;        /* aka slot_number or set to NO_PROC_ID */
83         unsigned long hpa;          /* Host Physical address */
84         unsigned long txn_addr;     /* MMIO addr of EIR or id_eid */
85 #ifdef CONFIG_SMP
86         spinlock_t lock;            /* synchronization for ipi's */
87         unsigned long pending_ipi;  /* bitmap of type ipi_message_type */
88         unsigned long ipi_count;    /* number ipi Interrupts */
89 #endif
90         unsigned long bh_count;     /* number of times bh was invoked */
91         unsigned long prof_counter; /* per CPU profiling support */
92         unsigned long prof_multiplier;  /* per CPU profiling support */
93         unsigned long fp_rev;
94         unsigned long fp_model;
95         unsigned int state;
96         struct parisc_device *dev;
97 };
98
99 extern struct system_cpuinfo_parisc boot_cpu_data;
100 extern struct cpuinfo_parisc cpu_data[NR_CPUS];
101 #define current_cpu_data cpu_data[smp_processor_id()]
102
103 #define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
104
105 #ifdef CONFIG_EISA
106 extern int EISA_bus;
107 #else
108 #define EISA_bus 0
109 #endif
110
111 #define MCA_bus 0
112 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
113
114 typedef struct {
115         int seg;  
116 } mm_segment_t;
117
118 struct thread_struct {
119         struct pt_regs regs;
120         unsigned long  task_size;
121         unsigned long  map_base;
122         unsigned long  flags;
123 }; 
124
125 /* Thread struct flags. */
126 #define PARISC_KERNEL_DEATH     (1UL << 31)     /* see die_if_kernel()... */
127
128 #define INIT_THREAD { \
129         regs:   {       gr: { 0, }, \
130                         fr: { 0, }, \
131                         sr: { 0, }, \
132                         iasq: { 0, }, \
133                         iaoq: { 0, }, \
134                         cr27: 0, \
135                 }, \
136         task_size:      DEFAULT_TASK_SIZE, \
137         map_base:       DEFAULT_MAP_BASE, \
138         flags:          0 \
139         }
140
141 /*
142  * Return saved PC of a blocked thread.  This is used by ps mostly.
143  */
144
145 static inline unsigned long thread_saved_pc(struct thread_struct *t)
146 {
147         return 0xabcdef;
148 }
149
150 /*
151  * Start user thread in another space.
152  *
153  * Note that we set both the iaoq and r31 to the new pc. When
154  * the kernel initially calls execve it will return through an
155  * rfi path that will use the values in the iaoq. The execve
156  * syscall path will return through the gateway page, and
157  * that uses r31 to branch to.
158  *
159  * For ELF we clear r23, because the dynamic linker uses it to pass
160  * the address of the finalizer function.
161  *
162  * We also initialize sr3 to an illegal value (illegal for our
163  * implementation, not for the architecture).
164  */
165
166 #define start_thread_som(regs, new_pc, new_sp) do {     \
167         unsigned long *sp = (unsigned long *)new_sp;    \
168         __u32 spaceid = (__u32)current->mm->context;    \
169         unsigned long pc = (unsigned long)new_pc;       \
170         /* offset pc for priv. level */                 \
171         pc |= 3;                                        \
172                                                         \
173         set_fs(USER_DS);                                \
174         regs->iasq[0] = spaceid;                        \
175         regs->iasq[1] = spaceid;                        \
176         regs->iaoq[0] = pc;                             \
177         regs->iaoq[1] = pc + 4;                         \
178         regs->sr[2] = LINUX_GATEWAY_SPACE;              \
179         regs->sr[3] = 0xffff;                           \
180         regs->sr[4] = spaceid;                          \
181         regs->sr[5] = spaceid;                          \
182         regs->sr[6] = spaceid;                          \
183         regs->sr[7] = spaceid;                          \
184         regs->gr[ 0] = USER_PSW;                        \
185         regs->gr[30] = ((new_sp)+63)&~63;               \
186         regs->gr[31] = pc;                              \
187                                                         \
188         get_user(regs->gr[26],&sp[0]);                  \
189         get_user(regs->gr[25],&sp[-1]);                 \
190         get_user(regs->gr[24],&sp[-2]);                 \
191         get_user(regs->gr[23],&sp[-3]);                 \
192 } while(0)
193
194 /* The ELF abi wants things done a "wee bit" differently than
195  * som does.  Supporting this behavior here avoids
196  * having our own version of create_elf_tables.
197  *
198  * Oh, and yes, that is not a typo, we are really passing argc in r25
199  * and argv in r24 (rather than r26 and r25).  This is because that's
200  * where __libc_start_main wants them.
201  *
202  * Duplicated from dl-machine.h for the benefit of readers:
203  *
204  *  Our initial stack layout is rather different from everyone else's
205  *  due to the unique PA-RISC ABI.  As far as I know it looks like
206  *  this:
207
208    -----------------------------------  (user startup code creates this frame)
209    |         32 bytes of magic       |
210    |---------------------------------|
211    | 32 bytes argument/sp save area  |
212    |---------------------------------| (bprm->p)
213    |        ELF auxiliary info       |
214    |         (up to 28 words)        |
215    |---------------------------------|
216    |               NULL              |
217    |---------------------------------|
218    |       Environment pointers      |
219    |---------------------------------|
220    |               NULL              |
221    |---------------------------------|
222    |        Argument pointers        |
223    |---------------------------------| <- argv
224    |          argc (1 word)          |
225    |---------------------------------| <- bprm->exec (HACK!)
226    |         N bytes of slack        |
227    |---------------------------------|
228    |    filename passed to execve    |
229    |---------------------------------| (mm->env_end)
230    |           env strings           |
231    |---------------------------------| (mm->env_start, mm->arg_end)
232    |           arg strings           |
233    |---------------------------------|
234    | additional faked arg strings if |
235    | we're invoked via binfmt_script |
236    |---------------------------------| (mm->arg_start)
237    stack base is at TASK_SIZE - rlim_max.
238
239 on downward growing arches, it looks like this:
240    stack base at TASK_SIZE
241    | filename passed to execve
242    | env strings
243    | arg strings
244    | faked arg strings
245    | slack
246    | ELF
247    | envps
248    | argvs
249    | argc
250
251  *  The pleasant part of this is that if we need to skip arguments we
252  *  can just decrement argc and move argv, because the stack pointer
253  *  is utterly unrelated to the location of the environment and
254  *  argument vectors.
255  *
256  * Note that the S/390 people took the easy way out and hacked their
257  * GCC to make the stack grow downwards.
258  */
259
260 #define start_thread(regs, new_pc, new_sp) do {         \
261         elf_addr_t *sp = (elf_addr_t *)new_sp;          \
262         __u32 spaceid = (__u32)current->mm->context;    \
263         elf_addr_t pc = (elf_addr_t)new_pc | 3;         \
264         elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1;      \
265                                                         \
266         set_fs(USER_DS);                                \
267         regs->iasq[0] = spaceid;                        \
268         regs->iasq[1] = spaceid;                        \
269         regs->iaoq[0] = pc;                             \
270         regs->iaoq[1] = pc + 4;                         \
271         regs->sr[2] = LINUX_GATEWAY_SPACE;              \
272         regs->sr[3] = 0xffff;                           \
273         regs->sr[4] = spaceid;                          \
274         regs->sr[5] = spaceid;                          \
275         regs->sr[6] = spaceid;                          \
276         regs->sr[7] = spaceid;                          \
277         regs->gr[ 0] = USER_PSW;                        \
278         regs->fr[ 0] = 0LL;                             \
279         regs->fr[ 1] = 0LL;                             \
280         regs->fr[ 2] = 0LL;                             \
281         regs->fr[ 3] = 0LL;                             \
282         regs->gr[30] = ((unsigned long)sp + 63) &~ 63;  \
283         regs->gr[31] = pc;                              \
284                                                         \
285         get_user(regs->gr[25], (argv - 1));             \
286         regs->gr[24] = (long) argv;                     \
287         regs->gr[23] = 0;                               \
288 } while(0)
289
290 struct task_struct;
291 struct mm_struct;
292
293 /* Free all resources held by a thread. */
294 extern void release_thread(struct task_struct *);
295 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
296
297 extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
298
299 #define copy_segments(tsk, mm)  do { \
300                                         if (tsk->personality == PER_HPUX)  \
301                                             map_hpux_gateway_page(tsk,mm); \
302                                 } while (0)
303 #define release_segments(mm)    do { } while (0)
304
305 static inline unsigned long get_wchan(struct task_struct *p)
306 {
307         return 0xdeadbeef; /* XXX */
308 }
309
310 #define KSTK_EIP(tsk)   ((tsk)->thread.regs.iaoq[0])
311 #define KSTK_ESP(tsk)   ((tsk)->thread.regs.gr[30])
312
313 #endif /* __ASSEMBLY__ */
314
315 #ifdef  CONFIG_PA20
316 #define ARCH_HAS_PREFETCH
317 extern inline void prefetch(const void *addr)
318 {
319         __asm__("ldw 0(%0), %%r0" : : "r" (addr));
320 }
321
322 #define ARCH_HAS_PREFETCHW
323 extern inline void prefetchw(const void *addr)
324 {
325         __asm__("ldd 0(%0), %%r0" : : "r" (addr));
326 }
327 #endif
328
329 /* Be sure to hunt all references to this down when you change the size of
330  * the kernel stack */
331
332 #define THREAD_SIZE     (4*PAGE_SIZE)
333
334 #define alloc_task_struct() \
335         ((struct task_struct *) __get_free_pages(GFP_KERNEL,2))
336 #define free_task_struct(p)     free_pages((unsigned long)(p),2)
337 #define get_task_struct(tsk)    atomic_inc(&virt_to_page(tsk)->count)
338
339 #define init_task (init_task_union.task) 
340 #define init_stack (init_task_union.stack)
341
342 #define cpu_relax()     do { } while (0)
343
344 #endif /* __ASM_PARISC_PROCESSOR_H */