| H. Peter Anvin | 1965aae | 2008-10-22 22:26:29 -0700 | [diff] [blame] | 1 | #ifndef _ASM_X86_PERCPU_H | 
 | 2 | #define _ASM_X86_PERCPU_H | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 3 |  | 
| Tejun Heo | 1a51e3a | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 4 | #ifdef CONFIG_X86_64 | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 5 | #define __percpu_seg		gs | 
 | 6 | #define __percpu_mov_op		movq | 
| Tejun Heo | 1a51e3a | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 7 | #else | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 8 | #define __percpu_seg		fs | 
 | 9 | #define __percpu_mov_op		movl | 
| Tejun Heo | 1a51e3a | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 10 | #endif | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 11 |  | 
 | 12 | #ifdef __ASSEMBLY__ | 
 | 13 |  | 
 | 14 | /* | 
 | 15 |  * PER_CPU finds an address of a per-cpu variable. | 
 | 16 |  * | 
 | 17 |  * Args: | 
 | 18 |  *    var - variable name | 
 | 19 |  *    reg - 32bit register | 
 | 20 |  * | 
 | 21 |  * The resulting address is stored in the "reg" argument. | 
 | 22 |  * | 
 | 23 |  * Example: | 
 | 24 |  *    PER_CPU(cpu_gdt_descr, %ebx) | 
 | 25 |  */ | 
 | 26 | #ifdef CONFIG_SMP | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 27 | #define PER_CPU(var, reg)						\ | 
 | 28 | 	__percpu_mov_op %__percpu_seg:per_cpu__this_cpu_off, reg;	\ | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 29 | 	lea per_cpu__##var(reg), reg | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 30 | #define PER_CPU_VAR(var)	%__percpu_seg:per_cpu__##var | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 31 | #else /* ! SMP */ | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 32 | #define PER_CPU(var, reg)						\ | 
 | 33 | 	__percpu_mov_op $per_cpu__##var, reg | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 34 | #define PER_CPU_VAR(var)	per_cpu__##var | 
 | 35 | #endif	/* SMP */ | 
 | 36 |  | 
 | 37 | #else /* ...!ASSEMBLY */ | 
 | 38 |  | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 39 | #include <linux/stringify.h> | 
 | 40 |  | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 41 | #ifdef CONFIG_SMP | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 42 | #define __percpu_arg(x)		"%%"__stringify(__percpu_seg)":%P" #x | 
| Ingo Molnar | 6dbde35 | 2009-01-15 22:15:53 +0900 | [diff] [blame] | 43 | #define __my_cpu_offset		percpu_read(this_cpu_off) | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 44 | #else | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 45 | #define __percpu_arg(x)		"%" #x | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 46 | #endif | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 47 |  | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 48 | /* For arch-specific code, we can use direct single-insn ops (they | 
 | 49 |  * don't give an lvalue though). */ | 
 | 50 | extern void __bad_percpu_size(void); | 
 | 51 |  | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 52 | #define percpu_to_op(op, var, val)			\ | 
 | 53 | do {							\ | 
 | 54 | 	typedef typeof(var) T__;			\ | 
 | 55 | 	if (0) {					\ | 
 | 56 | 		T__ tmp__;				\ | 
 | 57 | 		tmp__ = (val);				\ | 
 | 58 | 	}						\ | 
 | 59 | 	switch (sizeof(var)) {				\ | 
 | 60 | 	case 1:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 61 | 		asm(op "b %1,"__percpu_arg(0)		\ | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 62 | 		    : "+m" (var)			\ | 
 | 63 | 		    : "ri" ((T__)val));			\ | 
 | 64 | 		break;					\ | 
 | 65 | 	case 2:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 66 | 		asm(op "w %1,"__percpu_arg(0)		\ | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 67 | 		    : "+m" (var)			\ | 
 | 68 | 		    : "ri" ((T__)val));			\ | 
 | 69 | 		break;					\ | 
 | 70 | 	case 4:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 71 | 		asm(op "l %1,"__percpu_arg(0)		\ | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 72 | 		    : "+m" (var)			\ | 
 | 73 | 		    : "ri" ((T__)val));			\ | 
 | 74 | 		break;					\ | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 75 | 	case 8:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 76 | 		asm(op "q %1,"__percpu_arg(0)		\ | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 77 | 		    : "+m" (var)			\ | 
| Brian Gerst | 299e269 | 2009-01-21 17:26:05 +0900 | [diff] [blame] | 78 | 		    : "re" ((T__)val));			\ | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 79 | 		break;					\ | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 80 | 	default: __bad_percpu_size();			\ | 
 | 81 | 	}						\ | 
 | 82 | } while (0) | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 83 |  | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 84 | #define percpu_from_op(op, var)				\ | 
 | 85 | ({							\ | 
 | 86 | 	typeof(var) ret__;				\ | 
 | 87 | 	switch (sizeof(var)) {				\ | 
 | 88 | 	case 1:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 89 | 		asm(op "b "__percpu_arg(1)",%0"		\ | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 90 | 		    : "=r" (ret__)			\ | 
 | 91 | 		    : "m" (var));			\ | 
 | 92 | 		break;					\ | 
 | 93 | 	case 2:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 94 | 		asm(op "w "__percpu_arg(1)",%0"		\ | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 95 | 		    : "=r" (ret__)			\ | 
 | 96 | 		    : "m" (var));			\ | 
 | 97 | 		break;					\ | 
 | 98 | 	case 4:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 99 | 		asm(op "l "__percpu_arg(1)",%0"		\ | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 100 | 		    : "=r" (ret__)			\ | 
 | 101 | 		    : "m" (var));			\ | 
 | 102 | 		break;					\ | 
 | 103 | 	case 8:						\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 104 | 		asm(op "q "__percpu_arg(1)",%0"		\ | 
| Joe Perches | bc9e3be | 2008-03-23 01:03:06 -0700 | [diff] [blame] | 105 | 		    : "=r" (ret__)			\ | 
 | 106 | 		    : "m" (var));			\ | 
 | 107 | 		break;					\ | 
 | 108 | 	default: __bad_percpu_size();			\ | 
 | 109 | 	}						\ | 
 | 110 | 	ret__;						\ | 
 | 111 | }) | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 112 |  | 
| Ingo Molnar | 6dbde35 | 2009-01-15 22:15:53 +0900 | [diff] [blame] | 113 | #define percpu_read(var)	percpu_from_op("mov", per_cpu__##var) | 
 | 114 | #define percpu_write(var, val)	percpu_to_op("mov", per_cpu__##var, val) | 
 | 115 | #define percpu_add(var, val)	percpu_to_op("add", per_cpu__##var, val) | 
 | 116 | #define percpu_sub(var, val)	percpu_to_op("sub", per_cpu__##var, val) | 
 | 117 | #define percpu_and(var, val)	percpu_to_op("and", per_cpu__##var, val) | 
 | 118 | #define percpu_or(var, val)	percpu_to_op("or", per_cpu__##var, val) | 
 | 119 | #define percpu_xor(var, val)	percpu_to_op("xor", per_cpu__##var, val) | 
| Tejun Heo | 9939dda | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 120 |  | 
| Tejun Heo | 49357d1 | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 121 | /* This is not atomic against other CPUs -- CPU preemption needs to be off */ | 
 | 122 | #define x86_test_and_clear_bit_percpu(bit, var)				\ | 
 | 123 | ({									\ | 
 | 124 | 	int old__;							\ | 
| Brian Gerst | 87b2640 | 2009-01-19 00:38:59 +0900 | [diff] [blame] | 125 | 	asm volatile("btr %2,"__percpu_arg(1)"\n\tsbbl %0,%0"		\ | 
 | 126 | 		     : "=r" (old__), "+m" (per_cpu__##var)		\ | 
 | 127 | 		     : "dIr" (bit));					\ | 
| Tejun Heo | 49357d1 | 2009-01-13 20:41:35 +0900 | [diff] [blame] | 128 | 	old__;								\ | 
 | 129 | }) | 
 | 130 |  | 
| Ingo Molnar | 6dbde35 | 2009-01-15 22:15:53 +0900 | [diff] [blame] | 131 | #include <asm-generic/percpu.h> | 
 | 132 |  | 
 | 133 | /* We can use this directly for local CPU (faster). */ | 
 | 134 | DECLARE_PER_CPU(unsigned long, this_cpu_off); | 
 | 135 |  | 
| travis@sgi.com | 3334052 | 2008-01-30 13:32:53 +0100 | [diff] [blame] | 136 | #endif /* !__ASSEMBLY__ */ | 
| Mike Travis | 23ca4bb | 2008-05-12 21:21:12 +0200 | [diff] [blame] | 137 |  | 
 | 138 | #ifdef CONFIG_SMP | 
 | 139 |  | 
 | 140 | /* | 
 | 141 |  * Define the "EARLY_PER_CPU" macros.  These are used for some per_cpu | 
 | 142 |  * variables that are initialized and accessed before there are per_cpu | 
 | 143 |  * areas allocated. | 
 | 144 |  */ | 
 | 145 |  | 
 | 146 | #define	DEFINE_EARLY_PER_CPU(_type, _name, _initvalue)			\ | 
 | 147 | 	DEFINE_PER_CPU(_type, _name) = _initvalue;			\ | 
 | 148 | 	__typeof__(_type) _name##_early_map[NR_CPUS] __initdata =	\ | 
 | 149 | 				{ [0 ... NR_CPUS-1] = _initvalue };	\ | 
| Marcin Slusarz | c6a92a2 | 2008-08-17 17:50:50 +0200 | [diff] [blame] | 150 | 	__typeof__(_type) *_name##_early_ptr __refdata = _name##_early_map | 
| Mike Travis | 23ca4bb | 2008-05-12 21:21:12 +0200 | [diff] [blame] | 151 |  | 
 | 152 | #define EXPORT_EARLY_PER_CPU_SYMBOL(_name)			\ | 
 | 153 | 	EXPORT_PER_CPU_SYMBOL(_name) | 
 | 154 |  | 
 | 155 | #define DECLARE_EARLY_PER_CPU(_type, _name)			\ | 
 | 156 | 	DECLARE_PER_CPU(_type, _name);				\ | 
 | 157 | 	extern __typeof__(_type) *_name##_early_ptr;		\ | 
 | 158 | 	extern __typeof__(_type)  _name##_early_map[] | 
 | 159 |  | 
 | 160 | #define	early_per_cpu_ptr(_name) (_name##_early_ptr) | 
 | 161 | #define	early_per_cpu_map(_name, _idx) (_name##_early_map[_idx]) | 
 | 162 | #define	early_per_cpu(_name, _cpu) 				\ | 
| Tejun Heo | f10fcd4 | 2009-01-13 20:41:34 +0900 | [diff] [blame] | 163 | 	*(early_per_cpu_ptr(_name) ?				\ | 
 | 164 | 		&early_per_cpu_ptr(_name)[_cpu] :		\ | 
 | 165 | 		&per_cpu(_name, _cpu)) | 
| Mike Travis | 23ca4bb | 2008-05-12 21:21:12 +0200 | [diff] [blame] | 166 |  | 
 | 167 | #else	/* !CONFIG_SMP */ | 
 | 168 | #define	DEFINE_EARLY_PER_CPU(_type, _name, _initvalue)		\ | 
 | 169 | 	DEFINE_PER_CPU(_type, _name) = _initvalue | 
 | 170 |  | 
 | 171 | #define EXPORT_EARLY_PER_CPU_SYMBOL(_name)			\ | 
 | 172 | 	EXPORT_PER_CPU_SYMBOL(_name) | 
 | 173 |  | 
 | 174 | #define DECLARE_EARLY_PER_CPU(_type, _name)			\ | 
 | 175 | 	DECLARE_PER_CPU(_type, _name) | 
 | 176 |  | 
 | 177 | #define	early_per_cpu(_name, _cpu) per_cpu(_name, _cpu) | 
 | 178 | #define	early_per_cpu_ptr(_name) NULL | 
 | 179 | /* no early_per_cpu_map() */ | 
 | 180 |  | 
 | 181 | #endif	/* !CONFIG_SMP */ | 
 | 182 |  | 
| H. Peter Anvin | 1965aae | 2008-10-22 22:26:29 -0700 | [diff] [blame] | 183 | #endif /* _ASM_X86_PERCPU_H */ |