mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 17:12:06 +00:00
89cbc76768
__get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) Cc: Thomas Gleixner <tglx@linutronix.de> Cc: x86@kernel.org Acked-by: H. Peter Anvin <hpa@linux.intel.com> Acked-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Christoph Lameter <cl@linux.com> Signed-off-by: Tejun Heo <tj@kernel.org>
119 lines
2.5 KiB
C
119 lines
2.5 KiB
C
#ifndef _ASM_X86_DEBUGREG_H
|
|
#define _ASM_X86_DEBUGREG_H
|
|
|
|
|
|
#include <linux/bug.h>
|
|
#include <uapi/asm/debugreg.h>
|
|
|
|
DECLARE_PER_CPU(unsigned long, cpu_dr7);
|
|
|
|
#ifndef CONFIG_PARAVIRT
|
|
/*
|
|
* These special macros can be used to get or set a debugging register
|
|
*/
|
|
#define get_debugreg(var, register) \
|
|
(var) = native_get_debugreg(register)
|
|
#define set_debugreg(value, register) \
|
|
native_set_debugreg(register, value)
|
|
#endif
|
|
|
|
static inline unsigned long native_get_debugreg(int regno)
|
|
{
|
|
unsigned long val = 0; /* Damn you, gcc! */
|
|
|
|
switch (regno) {
|
|
case 0:
|
|
asm("mov %%db0, %0" :"=r" (val));
|
|
break;
|
|
case 1:
|
|
asm("mov %%db1, %0" :"=r" (val));
|
|
break;
|
|
case 2:
|
|
asm("mov %%db2, %0" :"=r" (val));
|
|
break;
|
|
case 3:
|
|
asm("mov %%db3, %0" :"=r" (val));
|
|
break;
|
|
case 6:
|
|
asm("mov %%db6, %0" :"=r" (val));
|
|
break;
|
|
case 7:
|
|
asm("mov %%db7, %0" :"=r" (val));
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
return val;
|
|
}
|
|
|
|
static inline void native_set_debugreg(int regno, unsigned long value)
|
|
{
|
|
switch (regno) {
|
|
case 0:
|
|
asm("mov %0, %%db0" ::"r" (value));
|
|
break;
|
|
case 1:
|
|
asm("mov %0, %%db1" ::"r" (value));
|
|
break;
|
|
case 2:
|
|
asm("mov %0, %%db2" ::"r" (value));
|
|
break;
|
|
case 3:
|
|
asm("mov %0, %%db3" ::"r" (value));
|
|
break;
|
|
case 6:
|
|
asm("mov %0, %%db6" ::"r" (value));
|
|
break;
|
|
case 7:
|
|
asm("mov %0, %%db7" ::"r" (value));
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
}
|
|
|
|
static inline void hw_breakpoint_disable(void)
|
|
{
|
|
/* Zero the control register for HW Breakpoint */
|
|
set_debugreg(0UL, 7);
|
|
|
|
/* Zero-out the individual HW breakpoint address registers */
|
|
set_debugreg(0UL, 0);
|
|
set_debugreg(0UL, 1);
|
|
set_debugreg(0UL, 2);
|
|
set_debugreg(0UL, 3);
|
|
}
|
|
|
|
static inline int hw_breakpoint_active(void)
|
|
{
|
|
return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
|
|
}
|
|
|
|
extern void aout_dump_debugregs(struct user *dump);
|
|
|
|
extern void hw_breakpoint_restore(void);
|
|
|
|
#ifdef CONFIG_X86_64
|
|
DECLARE_PER_CPU(int, debug_stack_usage);
|
|
static inline void debug_stack_usage_inc(void)
|
|
{
|
|
__this_cpu_inc(debug_stack_usage);
|
|
}
|
|
static inline void debug_stack_usage_dec(void)
|
|
{
|
|
__this_cpu_dec(debug_stack_usage);
|
|
}
|
|
int is_debug_stack(unsigned long addr);
|
|
void debug_stack_set_zero(void);
|
|
void debug_stack_reset(void);
|
|
#else /* !X86_64 */
|
|
static inline int is_debug_stack(unsigned long addr) { return 0; }
|
|
static inline void debug_stack_set_zero(void) { }
|
|
static inline void debug_stack_reset(void) { }
|
|
static inline void debug_stack_usage_inc(void) { }
|
|
static inline void debug_stack_usage_dec(void) { }
|
|
#endif /* X86_64 */
|
|
|
|
|
|
#endif /* _ASM_X86_DEBUGREG_H */
|