File: /usr/src/linux/include/asm-ia64/system.h
1 #ifndef _ASM_IA64_SYSTEM_H
2 #define _ASM_IA64_SYSTEM_H
3
4 /*
5 * System defines. Note that this is included both from .c and .S
6 * files, so it does only defines, not any C code. This is based
7 * on information published in the Processor Abstraction Layer
8 * and the System Abstraction Layer manual.
9 *
10 * Copyright (C) 1998-2001 Hewlett-Packard Co
11 * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
12 * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
13 * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
14 */
15 #include <linux/config.h>
16
17 #include <asm/page.h>
18
19 #define KERNEL_START (PAGE_OFFSET + 68*1024*1024)
20
21 /*
22 * The following #defines must match with vmlinux.lds.S:
23 */
24 #define IVT_ADDR (KERNEL_START)
25 #define IVT_END_ADDR (KERNEL_START + 0x8000)
26 #define ZERO_PAGE_ADDR PAGE_ALIGN(IVT_END_ADDR)
27 #define SWAPPER_PGD_ADDR (ZERO_PAGE_ADDR + 1*PAGE_SIZE)
28
29 #define GATE_ADDR (0xa000000000000000 + PAGE_SIZE)
30 #define PERCPU_ADDR (0xa000000000000000 + 2*PAGE_SIZE)
31
32 #if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
33 /* Workaround for Errata 97. */
34 # define IA64_SEMFIX_INSN mf;
35 # define IA64_SEMFIX "mf;"
36 #else
37 # define IA64_SEMFIX_INSN
38 # define IA64_SEMFIX ""
39 #endif
40
41 #ifndef __ASSEMBLY__
42
43 #include <linux/kernel.h>
44 #include <linux/types.h>
45
46 struct pci_vector_struct {
47 __u16 bus; /* PCI Bus number */
48 __u32 pci_id; /* ACPI split 16 bits device, 16 bits function (see section 6.1.1) */
49 __u8 pin; /* PCI PIN (0 = A, 1 = B, 2 = C, 3 = D) */
50 __u8 irq; /* IRQ assigned */
51 };
52
53 extern struct ia64_boot_param {
54 __u64 command_line; /* physical address of command line arguments */
55 __u64 efi_systab; /* physical address of EFI system table */
56 __u64 efi_memmap; /* physical address of EFI memory map */
57 __u64 efi_memmap_size; /* size of EFI memory map */
58 __u64 efi_memdesc_size; /* size of an EFI memory map descriptor */
59 __u32 efi_memdesc_version; /* memory descriptor version */
60 struct {
61 __u16 num_cols; /* number of columns on console output device */
62 __u16 num_rows; /* number of rows on console output device */
63 __u16 orig_x; /* cursor's x position */
64 __u16 orig_y; /* cursor's y position */
65 } console_info;
66 __u64 fpswa; /* physical address of the fpswa interface */
67 __u64 initrd_start;
68 __u64 initrd_size;
69 } *ia64_boot_param;
70
71 static inline void
72 ia64_insn_group_barrier (void)
73 {
74 __asm__ __volatile__ (";;" ::: "memory");
75 }
76
77 /*
78 * Macros to force memory ordering. In these descriptions, "previous"
79 * and "subsequent" refer to program order; "visible" means that all
80 * architecturally visible effects of a memory access have occurred
81 * (at a minimum, this means the memory has been read or written).
82 *
83 * wmb(): Guarantees that all preceding stores to memory-
84 * like regions are visible before any subsequent
85 * stores and that all following stores will be
86 * visible only after all previous stores.
87 * rmb(): Like wmb(), but for reads.
88 * mb(): wmb()/rmb() combo, i.e., all previous memory
89 * accesses are visible before all subsequent
90 * accesses and vice versa. This is also known as
91 * a "fence."
92 *
93 * Note: "mb()" and its variants cannot be used as a fence to order
94 * accesses to memory mapped I/O registers. For that, mf.a needs to
95 * be used. However, we don't want to always use mf.a because (a)
96 * it's (presumably) much slower than mf and (b) mf.a is supported for
97 * sequential memory pages only.
98 */
99 #define mb() __asm__ __volatile__ ("mf" ::: "memory")
100 #define rmb() mb()
101 #define wmb() mb()
102
103 #ifdef CONFIG_SMP
104 # define smp_mb() mb()
105 # define smp_rmb() rmb()
106 # define smp_wmb() wmb()
107 #else
108 # define smp_mb() barrier()
109 # define smp_rmb() barrier()
110 # define smp_wmb() barrier()
111 #endif
112
113 /*
114 * XXX check on these---I suspect what Linus really wants here is
115 * acquire vs release semantics but we can't discuss this stuff with
116 * Linus just yet. Grrr...
117 */
118 #define set_mb(var, value) do { (var) = (value); mb(); } while (0)
119 #define set_wmb(var, value) do { (var) = (value); mb(); } while (0)
120
121 /*
122 * The group barrier in front of the rsm & ssm are necessary to ensure
123 * that none of the previous instructions in the same group are
124 * affected by the rsm/ssm.
125 */
126 /* For spinlocks etc */
127
128 #ifdef CONFIG_IA64_DEBUG_IRQ
129
130 extern unsigned long last_cli_ip;
131
132 # define local_irq_save(x) \
133 do { \
134 unsigned long ip, psr; \
135 \
136 __asm__ __volatile__ ("mov %0=psr;; rsm psr.i;;" : "=r" (psr) :: "memory"); \
137 if (psr & (1UL << 14)) { \
138 __asm__ ("mov %0=ip" : "=r"(ip)); \
139 last_cli_ip = ip; \
140 } \
141 (x) = psr; \
142 } while (0)
143
144 # define local_irq_disable() \
145 do { \
146 unsigned long ip, psr; \
147 \
148 __asm__ __volatile__ ("mov %0=psr;; rsm psr.i;;" : "=r" (psr) :: "memory"); \
149 if (psr & (1UL << 14)) { \
150 __asm__ ("mov %0=ip" : "=r"(ip)); \
151 last_cli_ip = ip; \
152 } \
153 } while (0)
154
155 # define local_irq_restore(x) \
156 do { \
157 unsigned long ip, old_psr, psr = (x); \
158 \
159 __asm__ __volatile__ (";;mov %0=psr; mov psr.l=%1;; srlz.d" \
160 : "=&r" (old_psr) : "r" (psr) : "memory"); \
161 if ((old_psr & (1UL << 14)) && !(psr & (1UL << 14))) { \
162 __asm__ ("mov %0=ip" : "=r"(ip)); \
163 last_cli_ip = ip; \
164 } \
165 } while (0)
166
167 #else /* !CONFIG_IA64_DEBUG_IRQ */
168 /* clearing of psr.i is implicitly serialized (visible by next insn) */
169 # define local_irq_save(x) __asm__ __volatile__ ("mov %0=psr;; rsm psr.i;;" \
170 : "=r" (x) :: "memory")
171 # define local_irq_disable() __asm__ __volatile__ (";; rsm psr.i;;" ::: "memory")
172 /* (potentially) setting psr.i requires data serialization: */
173 # define local_irq_restore(x) __asm__ __volatile__ (";; mov psr.l=%0;; srlz.d" \
174 :: "r" (x) : "memory")
175 #endif /* !CONFIG_IA64_DEBUG_IRQ */
176
177 #define local_irq_enable() __asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory")
178
179 #define __cli() local_irq_disable ()
180 #define __save_flags(flags) __asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory")
181 #define __save_and_cli(flags) local_irq_save(flags)
182 #define save_and_cli(flags) __save_and_cli(flags)
183 #define __sti() local_irq_enable ()
184 #define __restore_flags(flags) local_irq_restore(flags)
185
186 #ifdef CONFIG_SMP
187 extern void __global_cli (void);
188 extern void __global_sti (void);
189 extern unsigned long __global_save_flags (void);
190 extern void __global_restore_flags (unsigned long);
191 # define cli() __global_cli()
192 # define sti() __global_sti()
193 # define save_flags(flags) ((flags) = __global_save_flags())
194 # define restore_flags(flags) __global_restore_flags(flags)
195 #else /* !CONFIG_SMP */
196 # define cli() __cli()
197 # define sti() __sti()
198 # define save_flags(flags) __save_flags(flags)
199 # define restore_flags(flags) __restore_flags(flags)
200 #endif /* !CONFIG_SMP */
201
202 /*
203 * Force an unresolved reference if someone tries to use
204 * ia64_fetch_and_add() with a bad value.
205 */
206 extern unsigned long __bad_size_for_ia64_fetch_and_add (void);
207 extern unsigned long __bad_increment_for_ia64_fetch_and_add (void);
208
209 #define IA64_FETCHADD(tmp,v,n,sz) \
210 ({ \
211 switch (sz) { \
212 case 4: \
213 __asm__ __volatile__ (IA64_SEMFIX"fetchadd4.rel %0=[%1],%2" \
214 : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \
215 break; \
216 \
217 case 8: \
218 __asm__ __volatile__ (IA64_SEMFIX"fetchadd8.rel %0=[%1],%2" \
219 : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \
220 break; \
221 \
222 default: \
223 __bad_size_for_ia64_fetch_and_add(); \
224 } \
225 })
226
227 #define ia64_fetch_and_add(i,v) \
228 ({ \
229 __u64 _tmp; \
230 volatile __typeof__(*(v)) *_v = (v); \
231 switch (i) { \
232 case -16: IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v))); break; \
233 case -8: IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v))); break; \
234 case -4: IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v))); break; \
235 case -1: IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v))); break; \
236 case 1: IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v))); break; \
237 case 4: IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v))); break; \
238 case 8: IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v))); break; \
239 case 16: IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v))); break; \
240 default: \
241 _tmp = __bad_increment_for_ia64_fetch_and_add(); \
242 break; \
243 } \
244 (__typeof__(*v)) (_tmp + (i)); /* return new value */ \
245 })
246
247 /*
248 * This function doesn't exist, so you'll get a linker error if
249 * something tries to do an invalid xchg().
250 */
251 extern void __xchg_called_with_bad_pointer (void);
252
253 static __inline__ unsigned long
254 __xchg (unsigned long x, volatile void *ptr, int size)
255 {
256 unsigned long result;
257
258 switch (size) {
259 case 1:
260 __asm__ __volatile (IA64_SEMFIX"xchg1 %0=[%1],%2" : "=r" (result)
261 : "r" (ptr), "r" (x) : "memory");
262 return result;
263
264 case 2:
265 __asm__ __volatile (IA64_SEMFIX"xchg2 %0=[%1],%2" : "=r" (result)
266 : "r" (ptr), "r" (x) : "memory");
267 return result;
268
269 case 4:
270 __asm__ __volatile (IA64_SEMFIX"xchg4 %0=[%1],%2" : "=r" (result)
271 : "r" (ptr), "r" (x) : "memory");
272 return result;
273
274 case 8:
275 __asm__ __volatile (IA64_SEMFIX"xchg8 %0=[%1],%2" : "=r" (result)
276 : "r" (ptr), "r" (x) : "memory");
277 return result;
278 }
279 __xchg_called_with_bad_pointer();
280 return x;
281 }
282
283 #define xchg(ptr,x) \
284 ((__typeof__(*(ptr))) __xchg ((unsigned long) (x), (ptr), sizeof(*(ptr))))
285
286 /*
287 * Atomic compare and exchange. Compare OLD with MEM, if identical,
288 * store NEW in MEM. Return the initial value in MEM. Success is
289 * indicated by comparing RETURN with OLD.
290 */
291
292 #define __HAVE_ARCH_CMPXCHG 1
293
294 /*
295 * This function doesn't exist, so you'll get a linker error
296 * if something tries to do an invalid cmpxchg().
297 */
298 extern long __cmpxchg_called_with_bad_pointer(void);
299
300 #define ia64_cmpxchg(sem,ptr,old,new,size) \
301 ({ \
302 __typeof__(ptr) _p_ = (ptr); \
303 __typeof__(new) _n_ = (new); \
304 __u64 _o_, _r_; \
305 \
306 switch (size) { \
307 case 1: _o_ = (__u8 ) (long) (old); break; \
308 case 2: _o_ = (__u16) (long) (old); break; \
309 case 4: _o_ = (__u32) (long) (old); break; \
310 case 8: _o_ = (__u64) (long) (old); break; \
311 default: break; \
312 } \
313 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \
314 switch (size) { \
315 case 1: \
316 __asm__ __volatile__ (IA64_SEMFIX"cmpxchg1."sem" %0=[%1],%2,ar.ccv" \
317 : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \
318 break; \
319 \
320 case 2: \
321 __asm__ __volatile__ (IA64_SEMFIX"cmpxchg2."sem" %0=[%1],%2,ar.ccv" \
322 : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \
323 break; \
324 \
325 case 4: \
326 __asm__ __volatile__ (IA64_SEMFIX"cmpxchg4."sem" %0=[%1],%2,ar.ccv" \
327 : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \
328 break; \
329 \
330 case 8: \
331 __asm__ __volatile__ (IA64_SEMFIX"cmpxchg8."sem" %0=[%1],%2,ar.ccv" \
332 : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \
333 break; \
334 \
335 default: \
336 _r_ = __cmpxchg_called_with_bad_pointer(); \
337 break; \
338 } \
339 (__typeof__(old)) _r_; \
340 })
341
342 #define cmpxchg_acq(ptr,o,n) ia64_cmpxchg("acq", (ptr), (o), (n), sizeof(*(ptr)))
343 #define cmpxchg_rel(ptr,o,n) ia64_cmpxchg("rel", (ptr), (o), (n), sizeof(*(ptr)))
344
345 /* for compatibility with other platforms: */
346 #define cmpxchg(ptr,o,n) cmpxchg_acq(ptr,o,n)
347
348 #ifdef CONFIG_IA64_DEBUG_CMPXCHG
349 # define CMPXCHG_BUGCHECK_DECL int _cmpxchg_bugcheck_count = 128;
350 # define CMPXCHG_BUGCHECK(v) \
351 do { \
352 if (_cmpxchg_bugcheck_count-- <= 0) { \
353 void *ip; \
354 extern int printk(const char *fmt, ...); \
355 asm ("mov %0=ip" : "=r"(ip)); \
356 printk("CMPXCHG_BUGCHECK: stuck at %p on word %p\n", ip, (v)); \
357 break; \
358 } \
359 } while (0)
360 #else /* !CONFIG_IA64_DEBUG_CMPXCHG */
361 # define CMPXCHG_BUGCHECK_DECL
362 # define CMPXCHG_BUGCHECK(v)
363 #endif /* !CONFIG_IA64_DEBUG_CMPXCHG */
364
365 #ifdef __KERNEL__
366
367 #define prepare_to_switch() do { } while(0)
368
369 #ifdef CONFIG_IA32_SUPPORT
370 # define IS_IA32_PROCESS(regs) (ia64_psr(regs)->is != 0)
371 #else
372 # define IS_IA32_PROCESS(regs) 0
373 #endif
374
375 /*
376 * Context switch from one thread to another. If the two threads have
377 * different address spaces, schedule() has already taken care of
378 * switching to the new address space by calling switch_mm().
379 *
380 * Disabling access to the fph partition and the debug-register
381 * context switch MUST be done before calling ia64_switch_to() since a
382 * newly created thread returns directly to
383 * ia64_ret_from_syscall_clear_r8.
384 */
385 extern struct task_struct *ia64_switch_to (void *next_task);
386
387 extern void ia64_save_extra (struct task_struct *task);
388 extern void ia64_load_extra (struct task_struct *task);
389
390 #define __switch_to(prev,next,last) do { \
391 if (((prev)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \
392 || IS_IA32_PROCESS(ia64_task_regs(prev))) \
393 ia64_save_extra(prev); \
394 if (((next)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \
395 || IS_IA32_PROCESS(ia64_task_regs(next))) \
396 ia64_load_extra(next); \
397 (last) = ia64_switch_to((next)); \
398 } while (0)
399
400 #ifdef CONFIG_SMP
401 /*
402 * In the SMP case, we save the fph state when context-switching
403 * away from a thread that modified fph. This way, when the thread
404 * gets scheduled on another CPU, the CPU can pick up the state from
405 * task->thread.fph, avoiding the complication of having to fetch
406 * the latest fph state from another CPU.
407 */
408 # define switch_to(prev,next,last) do { \
409 if (ia64_psr(ia64_task_regs(prev))->mfh) { \
410 ia64_psr(ia64_task_regs(prev))->mfh = 0; \
411 (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \
412 __ia64_save_fpu((prev)->thread.fph); \
413 } \
414 ia64_psr(ia64_task_regs(prev))->dfh = 1; \
415 __switch_to(prev,next,last); \
416 } while (0)
417 #else
418 # define switch_to(prev,next,last) do { \
419 ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next)); \
420 __switch_to(prev,next,last); \
421 } while (0)
422 #endif
423
424 #endif /* __KERNEL__ */
425
426 #endif /* __ASSEMBLY__ */
427
428 #endif /* _ASM_IA64_SYSTEM_H */
429