Commit 7c3576d2 authored by Jeremy Fitzhardinge's avatar Jeremy Fitzhardinge Committed by Andi Kleen

[PATCH] i386: Convert PDA into the percpu section

Currently x86 (similar to x84-64) has a special per-cpu structure
called "i386_pda" which can be easily and efficiently referenced via
the %fs register.  An ELF section is more flexible than a structure,
allowing any piece of code to use this area.  Indeed, such a section
already exists: the per-cpu area.

So this patch:
(1) Removes the PDA and uses per-cpu variables for each current member.
(2) Replaces the __KERNEL_PDA segment with __KERNEL_PERCPU.
(3) Creates a per-cpu mirror of __per_cpu_offset called this_cpu_off, which
    can be used to calculate addresses for this CPU's variables.
(4) Simplifies startup, because %fs doesn't need to be loaded with a
    special segment at early boot; it can be deferred until the first
    percpu area is allocated (or never for UP).

The result is less code and one less x86-specific concept.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarJeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Cc: Andi Kleen <ak@suse.de>
parent 7a61d35d
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/pda.h>
#define DEFINE(sym, val) \ #define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val)) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
...@@ -101,10 +100,6 @@ void foo(void) ...@@ -101,10 +100,6 @@ void foo(void)
OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
BLANK();
OFFSET(PDA_cpu, i386_pda, cpu_number);
OFFSET(PDA_pcurrent, i386_pda, pcurrent);
#ifdef CONFIG_PARAVIRT #ifdef CONFIG_PARAVIRT
BLANK(); BLANK();
OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled); OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled);
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <asm/apic.h> #include <asm/apic.h>
#include <mach_apic.h> #include <mach_apic.h>
#endif #endif
#include <asm/pda.h>
#include "cpu.h" #include "cpu.h"
...@@ -47,13 +46,10 @@ DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { ...@@ -47,13 +46,10 @@ DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
[GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */
[GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 },
[GDT_ENTRY_PDA] = { 0x00000000, 0x00c09200 }, /* set in setup_pda */ [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 },
} }; } };
EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
DEFINE_PER_CPU(struct i386_pda, _cpu_pda);
EXPORT_PER_CPU_SYMBOL(_cpu_pda);
static int cachesize_override __cpuinitdata = -1; static int cachesize_override __cpuinitdata = -1;
static int disable_x86_fxsr __cpuinitdata; static int disable_x86_fxsr __cpuinitdata;
static int disable_x86_serial_nr __cpuinitdata = 1; static int disable_x86_serial_nr __cpuinitdata = 1;
...@@ -634,21 +630,14 @@ void __init early_cpu_init(void) ...@@ -634,21 +630,14 @@ void __init early_cpu_init(void)
#endif #endif
} }
/* Make sure %gs is initialized properly in idle threads */ /* Make sure %fs is initialized properly in idle threads */
struct pt_regs * __devinit idle_regs(struct pt_regs *regs) struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
{ {
memset(regs, 0, sizeof(struct pt_regs)); memset(regs, 0, sizeof(struct pt_regs));
regs->xfs = __KERNEL_PDA; regs->xfs = __KERNEL_PERCPU;
return regs; return regs;
} }
/* Initial PDA used by boot CPU */
struct i386_pda boot_pda = {
._pda = &boot_pda,
.cpu_number = 0,
.pcurrent = &init_task,
};
/* /*
* cpu_init() initializes state that is per-CPU. Some data is already * cpu_init() initializes state that is per-CPU. Some data is already
* initialized (naturally) in the bootstrap process, such as the GDT * initialized (naturally) in the bootstrap process, such as the GDT
......
...@@ -132,7 +132,7 @@ VM_MASK = 0x00020000 ...@@ -132,7 +132,7 @@ VM_MASK = 0x00020000
movl $(__USER_DS), %edx; \ movl $(__USER_DS), %edx; \
movl %edx, %ds; \ movl %edx, %ds; \
movl %edx, %es; \ movl %edx, %es; \
movl $(__KERNEL_PDA), %edx; \ movl $(__KERNEL_PERCPU), %edx; \
movl %edx, %fs movl %edx, %fs
#define RESTORE_INT_REGS \ #define RESTORE_INT_REGS \
...@@ -556,7 +556,6 @@ END(syscall_badsys) ...@@ -556,7 +556,6 @@ END(syscall_badsys)
#define FIXUP_ESPFIX_STACK \ #define FIXUP_ESPFIX_STACK \
/* since we are on a wrong stack, we cant make it a C code :( */ \ /* since we are on a wrong stack, we cant make it a C code :( */ \
movl %fs:PDA_cpu, %ebx; \
PER_CPU(gdt_page, %ebx); \ PER_CPU(gdt_page, %ebx); \
GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
addl %esp, %eax; \ addl %esp, %eax; \
...@@ -681,7 +680,7 @@ error_code: ...@@ -681,7 +680,7 @@ error_code:
pushl %fs pushl %fs
CFI_ADJUST_CFA_OFFSET 4 CFI_ADJUST_CFA_OFFSET 4
/*CFI_REL_OFFSET fs, 0*/ /*CFI_REL_OFFSET fs, 0*/
movl $(__KERNEL_PDA), %ecx movl $(__KERNEL_PERCPU), %ecx
movl %ecx, %fs movl %ecx, %fs
UNWIND_ESPFIX_STACK UNWIND_ESPFIX_STACK
popl %ecx popl %ecx
......
...@@ -317,12 +317,12 @@ is386: movl $2,%ecx # set MP ...@@ -317,12 +317,12 @@ is386: movl $2,%ecx # set MP
movl %eax,%cr0 movl %eax,%cr0
call check_x87 call check_x87
call setup_pda
lgdt early_gdt_descr lgdt early_gdt_descr
lidt idt_descr lidt idt_descr
ljmp $(__KERNEL_CS),$1f ljmp $(__KERNEL_CS),$1f
1: movl $(__KERNEL_DS),%eax # reload all the segment registers 1: movl $(__KERNEL_DS),%eax # reload all the segment registers
movl %eax,%ss # after changing gdt. movl %eax,%ss # after changing gdt.
movl %eax,%fs # gets reset once there's real percpu
movl $(__USER_DS),%eax # DS/ES contains default USER segment movl $(__USER_DS),%eax # DS/ES contains default USER segment
movl %eax,%ds movl %eax,%ds
...@@ -332,16 +332,17 @@ is386: movl $2,%ecx # set MP ...@@ -332,16 +332,17 @@ is386: movl $2,%ecx # set MP
movl %eax,%gs movl %eax,%gs
lldt %ax lldt %ax
movl $(__KERNEL_PDA),%eax
mov %eax,%fs
cld # gcc2 wants the direction flag cleared at all times cld # gcc2 wants the direction flag cleared at all times
pushl $0 # fake return address for unwinder pushl $0 # fake return address for unwinder
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
movb ready, %cl movb ready, %cl
movb $1, ready movb $1, ready
cmpb $0,%cl # the first CPU calls start_kernel cmpb $0,%cl # the first CPU calls start_kernel
jne initialize_secondary # all other CPUs call initialize_secondary je 1f
movl $(__KERNEL_PERCPU), %eax
movl %eax,%fs # set this cpu's percpu
jmp initialize_secondary # all other CPUs call initialize_secondary
1:
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
jmp start_kernel jmp start_kernel
...@@ -364,23 +365,6 @@ check_x87: ...@@ -364,23 +365,6 @@ check_x87:
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
ret ret
/*
* Point the GDT at this CPU's PDA. On boot this will be
* cpu_gdt_table and boot_pda; for secondary CPUs, these will be
* that CPU's GDT and PDA.
*/
ENTRY(setup_pda)
/* get the PDA pointer */
movl start_pda, %eax
/* slot the PDA address into the GDT */
mov early_gdt_descr+2, %ecx
mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */
shr $16, %eax
mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */
mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */
ret
/* /*
* setup_idt * setup_idt
* *
...@@ -553,9 +537,6 @@ ENTRY(empty_zero_page) ...@@ -553,9 +537,6 @@ ENTRY(empty_zero_page)
* This starts the data section. * This starts the data section.
*/ */
.data .data
ENTRY(start_pda)
.long boot_pda
ENTRY(stack_start) ENTRY(stack_start)
.long init_thread_union+THREAD_SIZE .long init_thread_union+THREAD_SIZE
.long __BOOT_DS .long __BOOT_DS
......
...@@ -28,5 +28,3 @@ EXPORT_SYMBOL(__read_lock_failed); ...@@ -28,5 +28,3 @@ EXPORT_SYMBOL(__read_lock_failed);
#endif #endif
EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(_proxy_pda);
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
EXPORT_PER_CPU_SYMBOL(irq_stat); EXPORT_PER_CPU_SYMBOL(irq_stat);
DEFINE_PER_CPU(struct pt_regs *, irq_regs);
EXPORT_PER_CPU_SYMBOL(irq_regs);
/* /*
* 'what should we do if we get a hw irq event on an illegal vector'. * 'what should we do if we get a hw irq event on an illegal vector'.
* each architecture has to answer this themselves. * each architecture has to answer this themselves.
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/percpu.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -57,7 +58,6 @@ ...@@ -57,7 +58,6 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/pda.h>
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
...@@ -66,6 +66,12 @@ static int hlt_counter; ...@@ -66,6 +66,12 @@ static int hlt_counter;
unsigned long boot_option_idle_override = 0; unsigned long boot_option_idle_override = 0;
EXPORT_SYMBOL(boot_option_idle_override); EXPORT_SYMBOL(boot_option_idle_override);
DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
EXPORT_PER_CPU_SYMBOL(current_task);
DEFINE_PER_CPU(int, cpu_number);
EXPORT_PER_CPU_SYMBOL(cpu_number);
/* /*
* Return saved PC of a blocked thread. * Return saved PC of a blocked thread.
*/ */
...@@ -342,7 +348,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) ...@@ -342,7 +348,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
regs.xds = __USER_DS; regs.xds = __USER_DS;
regs.xes = __USER_DS; regs.xes = __USER_DS;
regs.xfs = __KERNEL_PDA; regs.xfs = __KERNEL_PERCPU;
regs.orig_eax = -1; regs.orig_eax = -1;
regs.eip = (unsigned long) kernel_thread_helper; regs.eip = (unsigned long) kernel_thread_helper;
regs.xcs = __KERNEL_CS | get_kernel_rpl(); regs.xcs = __KERNEL_CS | get_kernel_rpl();
...@@ -711,7 +717,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas ...@@ -711,7 +717,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
if (prev->gs | next->gs) if (prev->gs | next->gs)
loadsegment(gs, next->gs); loadsegment(gs, next->gs);
write_pda(pcurrent, next_p); x86_write_percpu(current_task, next_p);
return prev_p; return prev_p;
} }
......
...@@ -53,7 +53,6 @@ ...@@ -53,7 +53,6 @@
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/arch_hooks.h> #include <asm/arch_hooks.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/pda.h>
#include <mach_apic.h> #include <mach_apic.h>
#include <mach_wakecpu.h> #include <mach_wakecpu.h>
...@@ -99,6 +98,9 @@ EXPORT_SYMBOL(x86_cpu_to_apicid); ...@@ -99,6 +98,9 @@ EXPORT_SYMBOL(x86_cpu_to_apicid);
u8 apicid_2_node[MAX_APICID]; u8 apicid_2_node[MAX_APICID];
DEFINE_PER_CPU(unsigned long, this_cpu_off);
EXPORT_PER_CPU_SYMBOL(this_cpu_off);
/* /*
* Trampoline 80x86 program as an array. * Trampoline 80x86 program as an array.
*/ */
...@@ -456,7 +458,6 @@ extern struct { ...@@ -456,7 +458,6 @@ extern struct {
void * esp; void * esp;
unsigned short ss; unsigned short ss;
} stack_start; } stack_start;
extern struct i386_pda *start_pda;
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
...@@ -784,20 +785,17 @@ static inline struct task_struct * alloc_idle_task(int cpu) ...@@ -784,20 +785,17 @@ static inline struct task_struct * alloc_idle_task(int cpu)
/* Initialize the CPU's GDT. This is either the boot CPU doing itself /* Initialize the CPU's GDT. This is either the boot CPU doing itself
(still using the master per-cpu area), or a CPU doing it for a (still using the master per-cpu area), or a CPU doing it for a
secondary which will soon come up. */ secondary which will soon come up. */
static __cpuinit void init_gdt(int cpu, struct task_struct *idle) static __cpuinit void init_gdt(int cpu)
{ {
struct desc_struct *gdt = get_cpu_gdt_table(cpu); struct desc_struct *gdt = get_cpu_gdt_table(cpu);
struct i386_pda *pda = &per_cpu(_cpu_pda, cpu);
pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, pack_descriptor((u32 *)&gdt[GDT_ENTRY_PERCPU].a,
(u32 *)&gdt[GDT_ENTRY_PDA].b, (u32 *)&gdt[GDT_ENTRY_PERCPU].b,
(unsigned long)pda, sizeof(*pda) - 1, __per_cpu_offset[cpu], 0xFFFFF,
0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */ 0x80 | DESCTYPE_S | 0x2, 0x8);
memset(pda, 0, sizeof(*pda)); per_cpu(this_cpu_off, cpu) = __per_cpu_offset[cpu];
pda->_pda = pda; per_cpu(cpu_number, cpu) = cpu;
pda->cpu_number = cpu;
pda->pcurrent = idle;
} }
/* Defined in head.S */ /* Defined in head.S */
...@@ -824,9 +822,9 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu) ...@@ -824,9 +822,9 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
if (IS_ERR(idle)) if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu); panic("failed fork for CPU %d", cpu);
init_gdt(cpu, idle); init_gdt(cpu);
per_cpu(current_task, cpu) = idle;
early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
start_pda = cpu_pda(cpu);
idle->thread.eip = (unsigned long) start_secondary; idle->thread.eip = (unsigned long) start_secondary;
/* start_eip had better be page-aligned! */ /* start_eip had better be page-aligned! */
...@@ -1188,14 +1186,14 @@ static inline void switch_to_new_gdt(void) ...@@ -1188,14 +1186,14 @@ static inline void switch_to_new_gdt(void)
gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id()); gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
gdt_descr.size = GDT_SIZE - 1; gdt_descr.size = GDT_SIZE - 1;
load_gdt(&gdt_descr); load_gdt(&gdt_descr);
asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory"); asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
} }
void __init native_smp_prepare_boot_cpu(void) void __init native_smp_prepare_boot_cpu(void)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
init_gdt(cpu, current); init_gdt(cpu);
switch_to_new_gdt(); switch_to_new_gdt();
cpu_set(cpu, cpu_online_map); cpu_set(cpu, cpu_online_map);
......
...@@ -504,8 +504,6 @@ static void vmi_pmd_clear(pmd_t *pmd) ...@@ -504,8 +504,6 @@ static void vmi_pmd_clear(pmd_t *pmd)
#endif #endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
extern void setup_pda(void);
static void __devinit static void __devinit
vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
unsigned long start_esp) unsigned long start_esp)
...@@ -530,13 +528,11 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, ...@@ -530,13 +528,11 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
ap.ds = __USER_DS; ap.ds = __USER_DS;
ap.es = __USER_DS; ap.es = __USER_DS;
ap.fs = __KERNEL_PDA; ap.fs = __KERNEL_PERCPU;
ap.gs = 0; ap.gs = 0;
ap.eflags = 0; ap.eflags = 0;
setup_pda();
#ifdef CONFIG_X86_PAE #ifdef CONFIG_X86_PAE
/* efer should match BSP efer. */ /* efer should match BSP efer. */
if (cpu_has_nx) { if (cpu_has_nx) {
......
...@@ -26,7 +26,6 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") ...@@ -26,7 +26,6 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386) OUTPUT_ARCH(i386)
ENTRY(phys_startup_32) ENTRY(phys_startup_32)
jiffies = jiffies_64; jiffies = jiffies_64;
_proxy_pda = 1;
PHDRS { PHDRS {
text PT_LOAD FLAGS(5); /* R_E */ text PT_LOAD FLAGS(5); /* R_E */
......
#ifndef _I386_CURRENT_H #ifndef _I386_CURRENT_H
#define _I386_CURRENT_H #define _I386_CURRENT_H
#include <asm/pda.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <asm/percpu.h>
struct task_struct; struct task_struct;
DECLARE_PER_CPU(struct task_struct *, current_task);
static __always_inline struct task_struct *get_current(void) static __always_inline struct task_struct *get_current(void)
{ {
return read_pda(pcurrent); return x86_read_percpu(current_task);
} }
#define current get_current() #define current get_current()
......
/* /*
* Per-cpu current frame pointer - the location of the last exception frame on * Per-cpu current frame pointer - the location of the last exception frame on
* the stack, stored in the PDA. * the stack, stored in the per-cpu area.
* *
* Jeremy Fitzhardinge <jeremy@goop.org> * Jeremy Fitzhardinge <jeremy@goop.org>
*/ */
#ifndef _ASM_I386_IRQ_REGS_H #ifndef _ASM_I386_IRQ_REGS_H
#define _ASM_I386_IRQ_REGS_H #define _ASM_I386_IRQ_REGS_H
#include <asm/pda.h> #include <asm/percpu.h>
DECLARE_PER_CPU(struct pt_regs *, irq_regs);
static inline struct pt_regs *get_irq_regs(void) static inline struct pt_regs *get_irq_regs(void)
{ {
return read_pda(irq_regs); return x86_read_percpu(irq_regs);
} }
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
{ {
struct pt_regs *old_regs; struct pt_regs *old_regs;
old_regs = read_pda(irq_regs); old_regs = get_irq_regs();
write_pda(irq_regs, new_regs); x86_write_percpu(irq_regs, new_regs);
return old_regs; return old_regs;
} }
......
/*
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>
#include <linux/types.h>
#include <asm/percpu.h>
struct i386_pda
{
struct i386_pda *_pda; /* pointer to self */
int cpu_number;
struct task_struct *pcurrent; /* current process */
struct pt_regs *irq_regs;
};
DECLARE_PER_CPU(struct i386_pda, _cpu_pda);
#define cpu_pda(i) (&per_cpu(_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,%%fs:%c2" \
: "+m" (_proxy_pda.field) \
:"ri" ((T__)val), \
"i"(pda_offset(field))); \
break; \
case 2: \
asm(op "w %1,%%fs:%c2" \
: "+m" (_proxy_pda.field) \
:"ri" ((T__)val), \
"i"(pda_offset(field))); \
break; \
case 4: \
asm(op "l %1,%%fs:%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 %%fs:%c1,%0" \
: "=r" (ret__) \
: "i" (pda_offset(field)), \
"m" (_proxy_pda.field)); \
break; \
case 2: \
asm(op "w %%fs:%c1,%0" \
: "=r" (ret__) \
: "i" (pda_offset(field)), \
"m" (_proxy_pda.field)); \
break; \
case 4: \
asm(op "l %%fs:%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 */
#ifndef __ARCH_I386_PERCPU__ #ifndef __ARCH_I386_PERCPU__
#define __ARCH_I386_PERCPU__ #define __ARCH_I386_PERCPU__
#ifndef __ASSEMBLY__ #ifdef __ASSEMBLY__
#include <asm-generic/percpu.h>
#else /*
* PER_CPU finds an address of a per-cpu variable.
*
* Args:
* var - variable name
* reg - 32bit register
*
* The resulting address is stored in the "reg" argument.
*
* Example:
* PER_CPU(cpu_gdt_descr, %ebx)
*/
#ifdef CONFIG_SMP
#define PER_CPU(var, reg) \
movl %fs:per_cpu__this_cpu_off, reg; \
addl $per_cpu__##var, reg
#else /* ! SMP */
#define PER_CPU(var, reg) \
movl $per_cpu__##var, reg;
#endif /* SMP */
#else /* ...!ASSEMBLY */
/* /*
* PER_CPU finds an address of a per-cpu variable. * PER_CPU finds an address of a per-cpu variable.
...@@ -18,14 +39,107 @@ ...@@ -18,14 +39,107 @@
* PER_CPU(cpu_gdt_descr, %ebx) * PER_CPU(cpu_gdt_descr, %ebx)
*/ */
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#define PER_CPU(var, cpu) \ /* Same as generic implementation except for optimized local access. */
movl __per_cpu_offset(,cpu,4), cpu; \ #define __GENERIC_PER_CPU
addl $per_cpu__##var, cpu;
#else /* ! SMP */ /* This is used for other cpus to find our section. */
#define PER_CPU(var, cpu) \ extern unsigned long __per_cpu_offset[];
movl $per_cpu__##var, cpu;
/* Separate out the type, so (int[3], foo) works. */
#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
/* We can use this directly for local CPU (faster). */
DECLARE_PER_CPU(unsigned long, this_cpu_off);
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*({ \
extern int simple_indentifier_##var(void); \
RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); }))
#define __raw_get_cpu_var(var) (*({ \
extern int simple_indentifier_##var(void); \
RELOC_HIDE(&per_cpu__##var, x86_read_percpu(this_cpu_off)); \
}))
#define __get_cpu_var(var) __raw_get_cpu_var(var)
/* A macro to avoid #include hell... */
#define percpu_modcopy(pcpudst, src, size) \
do { \
unsigned int __i; \
for_each_possible_cpu(__i) \
memcpy((pcpudst)+__per_cpu_offset[__i], \
(src), (size)); \
} while (0)
#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
/* fs segment starts at (positive) offset == __per_cpu_offset[cpu] */
#define __percpu_seg "%%fs:"
#else /* !SMP */
#include <asm-generic/percpu.h>
#define __percpu_seg ""
#endif /* SMP */ #endif /* SMP */
/* For arch-specific code, we can use direct single-insn ops (they
* don't give an lvalue though). */
extern void __bad_percpu_size(void);
#define percpu_to_op(op,var,val) \
do { \
typedef typeof(var) T__; \
if (0) { T__ tmp__; tmp__ = (val); } \
switch (sizeof(var)) { \
case 1: \
asm(op "b %1,"__percpu_seg"%0" \
: "+m" (var) \
:"ri" ((T__)val)); \
break; \
case 2: \
asm(op "w %1,"__percpu_seg"%0" \
: "+m" (var) \
:"ri" ((T__)val)); \
break; \
case 4: \
asm(op "l %1,"__percpu_seg"%0" \
: "+m" (var) \
:"ri" ((T__)val)); \
break; \
default: __bad_percpu_size(); \
} \
} while (0)
#define percpu_from_op(op,var) \
({ \
typeof(var) ret__; \
switch (sizeof(var)) { \
case 1: \
asm(op "b "__percpu_seg"%1,%0" \
: "=r" (ret__) \
: "m" (var)); \
break; \
case 2: \
asm(op "w "__percpu_seg"%1,%0" \
: "=r" (ret__) \
: "m" (var)); \
break; \
case 4: \
asm(op "l "__percpu_seg"%1,%0" \
: "=r" (ret__) \
: "m" (var)); \
break; \
default: __bad_percpu_size(); \
} \
ret__; })
#define x86_read_percpu(var) percpu_from_op("mov", per_cpu__##var)
#define x86_write_percpu(var,val) percpu_to_op("mov", per_cpu__##var, val)
#define x86_add_percpu(var,val) percpu_to_op("add", per_cpu__##var, val)
#define x86_sub_percpu(var,val) percpu_to_op("sub", per_cpu__##var, val)
#define x86_or_percpu(var,val) percpu_to_op("or", per_cpu__##var, val)
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
#endif /* __ARCH_I386_PERCPU__ */ #endif /* __ARCH_I386_PERCPU__ */
...@@ -377,7 +377,7 @@ struct thread_struct { ...@@ -377,7 +377,7 @@ struct thread_struct {
.vm86_info = NULL, \ .vm86_info = NULL, \
.sysenter_cs = __KERNEL_CS, \ .sysenter_cs = __KERNEL_CS, \
.io_bitmap_ptr = NULL, \ .io_bitmap_ptr = NULL, \
.fs = __KERNEL_PDA, \ .fs = __KERNEL_PERCPU, \
} }
/* /*
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* 25 - APM BIOS support * 25 - APM BIOS support
* *
* 26 - ESPFIX small SS * 26 - ESPFIX small SS
* 27 - PDA [ per-cpu private data area ] * 27 - per-cpu [ offset to per-cpu data area ]
* 28 - unused * 28 - unused
* 29 - unused * 29 - unused
* 30 - unused * 30 - unused
...@@ -74,8 +74,8 @@ ...@@ -74,8 +74,8 @@
#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14) #define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14)
#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8) #define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
#define GDT_ENTRY_PDA (GDT_ENTRY_KERNEL_BASE + 15) #define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15)
#define __KERNEL_PDA (GDT_ENTRY_PDA * 8) #define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8)
#define GDT_ENTRY_DOUBLEFAULT_TSS 31 #define GDT_ENTRY_DOUBLEFAULT_TSS 31
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <asm/pda.h>
#endif #endif
#if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__) #if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__)
...@@ -112,7 +111,8 @@ do { } while (0) ...@@ -112,7 +111,8 @@ do { } while (0)
* from the initial startup. We map APIC_BASE very early in page_setup(), * from the initial startup. We map APIC_BASE very early in page_setup(),
* so this is correct in the x86 case. * so this is correct in the x86 case.
*/ */
#define raw_smp_processor_id() (read_pda(cpu_number)) DECLARE_PER_CPU(int, cpu_number);
#define raw_smp_processor_id() (x86_read_percpu(cpu_number))
extern cpumask_t cpu_callout_map; extern cpumask_t cpu_callout_map;
extern cpumask_t cpu_callin_map; extern cpumask_t cpu_callin_map;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment