b2938f8808
Use the cpu_number in the PDA to implement raw_smp_processor_id. This is a little simpler than using thread_info, though the cpu field in thread_info cannot be removed since it is used for things other than getting the current CPU in common code. Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Chuck Ebbert <76306.1226@compuserve.com> Cc: Zachary Amsden <zach@vmware.com> Cc: Jan Beulich <jbeulich@novell.com> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org>
97 lines
2.6 KiB
C
97 lines
2.6 KiB
C
/*
|
|
Per-processor Data Areas
|
|
Jeremy Fitzhardinge <jeremy@goop.org> 2006
|
|
Based on asm-x86_64/pda.h by Andi Kleen.
|
|
*/
|
|
#ifndef _I386_PDA_H
|
|
#define _I386_PDA_H
|
|
|
|
#include <linux/stddef.h>
|
|
|
|
struct i386_pda
|
|
{
|
|
struct i386_pda *_pda; /* pointer to self */
|
|
|
|
int cpu_number;
|
|
};
|
|
|
|
extern struct i386_pda *_cpu_pda[];
|
|
|
|
#define cpu_pda(i) (_cpu_pda[i])
|
|
|
|
#define pda_offset(field) offsetof(struct i386_pda, field)
|
|
|
|
extern void __bad_pda_field(void);
|
|
|
|
/* This variable is never instantiated. It is only used as a stand-in
|
|
for the real per-cpu PDA memory, so that gcc can understand what
|
|
memory operations the inline asms() below are performing. This
|
|
eliminates the need to make the asms volatile or have memory
|
|
clobbers, so gcc can readily analyse them. */
|
|
extern struct i386_pda _proxy_pda;
|
|
|
|
#define pda_to_op(op,field,val) \
|
|
do { \
|
|
typedef typeof(_proxy_pda.field) T__; \
|
|
if (0) { T__ tmp__; tmp__ = (val); } \
|
|
switch (sizeof(_proxy_pda.field)) { \
|
|
case 1: \
|
|
asm(op "b %1,%%gs:%c2" \
|
|
: "+m" (_proxy_pda.field) \
|
|
:"ri" ((T__)val), \
|
|
"i"(pda_offset(field))); \
|
|
break; \
|
|
case 2: \
|
|
asm(op "w %1,%%gs:%c2" \
|
|
: "+m" (_proxy_pda.field) \
|
|
:"ri" ((T__)val), \
|
|
"i"(pda_offset(field))); \
|
|
break; \
|
|
case 4: \
|
|
asm(op "l %1,%%gs:%c2" \
|
|
: "+m" (_proxy_pda.field) \
|
|
:"ri" ((T__)val), \
|
|
"i"(pda_offset(field))); \
|
|
break; \
|
|
default: __bad_pda_field(); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define pda_from_op(op,field) \
|
|
({ \
|
|
typeof(_proxy_pda.field) ret__; \
|
|
switch (sizeof(_proxy_pda.field)) { \
|
|
case 1: \
|
|
asm(op "b %%gs:%c1,%0" \
|
|
: "=r" (ret__) \
|
|
: "i" (pda_offset(field)), \
|
|
"m" (_proxy_pda.field)); \
|
|
break; \
|
|
case 2: \
|
|
asm(op "w %%gs:%c1,%0" \
|
|
: "=r" (ret__) \
|
|
: "i" (pda_offset(field)), \
|
|
"m" (_proxy_pda.field)); \
|
|
break; \
|
|
case 4: \
|
|
asm(op "l %%gs:%c1,%0" \
|
|
: "=r" (ret__) \
|
|
: "i" (pda_offset(field)), \
|
|
"m" (_proxy_pda.field)); \
|
|
break; \
|
|
default: __bad_pda_field(); \
|
|
} \
|
|
ret__; })
|
|
|
|
/* Return a pointer to a pda field */
|
|
#define pda_addr(field) \
|
|
((typeof(_proxy_pda.field) *)((unsigned char *)read_pda(_pda) + \
|
|
pda_offset(field)))
|
|
|
|
#define read_pda(field) pda_from_op("mov",field)
|
|
#define write_pda(field,val) pda_to_op("mov",field,val)
|
|
#define add_pda(field,val) pda_to_op("add",field,val)
|
|
#define sub_pda(field,val) pda_to_op("sub",field,val)
|
|
#define or_pda(field,val) pda_to_op("or",field,val)
|
|
|
|
#endif /* _I386_PDA_H */
|