[POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers
[linux-2.6.git] / arch / x86_64 / vdso / vgetcpu.c
1 /*
2  * Copyright 2006 Andi Kleen, SUSE Labs.
3  * Subject to the GNU Public License, v.2
4  *
5  * Fast user context implementation of getcpu()
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/getcpu.h>
10 #include <linux/jiffies.h>
11 #include <linux/time.h>
12 #include <asm/vsyscall.h>
13 #include <asm/vgtod.h>
14 #include "vextern.h"
15
16 long __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
17 {
18         unsigned int dummy, p;
19         unsigned long j = 0;
20
21         /* Fast cache - only recompute value once per jiffies and avoid
22            relatively costly rdtscp/cpuid otherwise.
23            This works because the scheduler usually keeps the process
24            on the same CPU and this syscall doesn't guarantee its
25            results anyways.
26            We do this here because otherwise user space would do it on
27            its own in a likely inferior way (no access to jiffies).
28            If you don't like it pass NULL. */
29         if (tcache && tcache->blob[0] == (j = *vdso_jiffies)) {
30                 p = tcache->blob[1];
31         } else if (*vdso_vgetcpu_mode == VGETCPU_RDTSCP) {
32                 /* Load per CPU data from RDTSCP */
33                 rdtscp(dummy, dummy, p);
34         } else {
35                 /* Load per CPU data from GDT */
36                 asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
37         }
38         if (tcache) {
39                 tcache->blob[0] = j;
40                 tcache->blob[1] = p;
41         }
42         if (cpu)
43                 *cpu = p & 0xfff;
44         if (node)
45                 *node = p >> 12;
46         return 0;
47 }
48
49 long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
50         __attribute__((weak, alias("__vdso_getcpu")));