| /* | 
 |  * Copyright 2006 Andi Kleen, SUSE Labs. | 
 |  * Subject to the GNU Public License, v.2 | 
 |  * | 
 |  * Fast user context implementation of getcpu() | 
 |  */ | 
 |  | 
 | #include <linux/kernel.h> | 
 | #include <linux/getcpu.h> | 
 | #include <linux/jiffies.h> | 
 | #include <linux/time.h> | 
 | #include <asm/vsyscall.h> | 
 | #include <asm/vgtod.h> | 
 | #include "vextern.h" | 
 |  | 
 | long __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) | 
 | { | 
 | 	unsigned int dummy, p; | 
 | 	unsigned long j = 0; | 
 |  | 
 | 	/* Fast cache - only recompute value once per jiffies and avoid | 
 | 	   relatively costly rdtscp/cpuid otherwise. | 
 | 	   This works because the scheduler usually keeps the process | 
 | 	   on the same CPU and this syscall doesn't guarantee its | 
 | 	   results anyways. | 
 | 	   We do this here because otherwise user space would do it on | 
 | 	   its own in a likely inferior way (no access to jiffies). | 
 | 	   If you don't like it pass NULL. */ | 
 | 	if (tcache && tcache->blob[0] == (j = *vdso_jiffies)) { | 
 | 		p = tcache->blob[1]; | 
 | 	} else if (*vdso_vgetcpu_mode == VGETCPU_RDTSCP) { | 
 | 		/* Load per CPU data from RDTSCP */ | 
 | 		rdtscp(dummy, dummy, p); | 
 | 	} else { | 
 | 		/* Load per CPU data from GDT */ | 
 | 		asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); | 
 | 	} | 
 | 	if (tcache) { | 
 | 		tcache->blob[0] = j; | 
 | 		tcache->blob[1] = p; | 
 | 	} | 
 | 	if (cpu) | 
 | 		*cpu = p & 0xfff; | 
 | 	if (node) | 
 | 		*node = p >> 12; | 
 | 	return 0; | 
 | } | 
 |  | 
 | long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) | 
 | 	__attribute__((weak, alias("__vdso_getcpu"))); |