diff options
Diffstat (limited to 'arch/i386/kernel/smpboot.c')
-rw-r--r-- | arch/i386/kernel/smpboot.c | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index b36a5f174cc9..a9447c3e86dd 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
@@ -440,12 +440,6 @@ static void __cpuinit start_secondary(void *unused) | |||
440 | void __devinit initialize_secondary(void) | 440 | void __devinit initialize_secondary(void) |
441 | { | 441 | { |
442 | /* | 442 | /* |
443 | * switch to the per CPU GDT we already set up | ||
444 | * in do_boot_cpu() | ||
445 | */ | ||
446 | cpu_set_gdt(current_thread_info()->cpu); | ||
447 | |||
448 | /* | ||
449 | * We don't actually need to load the full TSS, | 443 | * We don't actually need to load the full TSS, |
450 | * basically just the stack pointer and the eip. | 444 | * basically just the stack pointer and the eip. |
451 | */ | 445 | */ |
@@ -787,6 +781,32 @@ static inline struct task_struct * alloc_idle_task(int cpu) | |||
787 | #define alloc_idle_task(cpu) fork_idle(cpu) | 781 | #define alloc_idle_task(cpu) fork_idle(cpu) |
788 | #endif | 782 | #endif |
789 | 783 | ||
784 | /* Initialize the CPU's GDT. This is either the boot CPU doing itself | ||
785 | (still using the master per-cpu area), or a CPU doing it for a | ||
786 | secondary which will soon come up. */ | ||
787 | static __cpuinit void init_gdt(int cpu, struct task_struct *idle) | ||
788 | { | ||
789 | struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); | ||
790 | struct desc_struct *gdt = per_cpu(cpu_gdt, cpu); | ||
791 | struct i386_pda *pda = &per_cpu(_cpu_pda, cpu); | ||
792 | |||
793 | cpu_gdt_descr->address = (unsigned long)gdt; | ||
794 | cpu_gdt_descr->size = GDT_SIZE - 1; | ||
795 | |||
796 | pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, | ||
797 | (u32 *)&gdt[GDT_ENTRY_PDA].b, | ||
798 | (unsigned long)pda, sizeof(*pda) - 1, | ||
799 | 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */ | ||
800 | |||
801 | memset(pda, 0, sizeof(*pda)); | ||
802 | pda->_pda = pda; | ||
803 | pda->cpu_number = cpu; | ||
804 | pda->pcurrent = idle; | ||
805 | } | ||
806 | |||
807 | /* Defined in head.S */ | ||
808 | extern struct Xgt_desc_struct early_gdt_descr; | ||
809 | |||
790 | static int __cpuinit do_boot_cpu(int apicid, int cpu) | 810 | static int __cpuinit do_boot_cpu(int apicid, int cpu) |
791 | /* | 811 | /* |
792 | * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad | 812 | * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad |
@@ -809,6 +829,8 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu) | |||
809 | panic("failed fork for CPU %d", cpu); | 829 | panic("failed fork for CPU %d", cpu); |
810 | 830 | ||
811 | init_gdt(cpu, idle); | 831 | init_gdt(cpu, idle); |
832 | early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); | ||
833 | start_pda = cpu_pda(cpu); | ||
812 | 834 | ||
813 | idle->thread.eip = (unsigned long) start_secondary; | 835 | idle->thread.eip = (unsigned long) start_secondary; |
814 | /* start_eip had better be page-aligned! */ | 836 | /* start_eip had better be page-aligned! */ |
@@ -1161,13 +1183,26 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
1161 | smp_boot_cpus(max_cpus); | 1183 | smp_boot_cpus(max_cpus); |
1162 | } | 1184 | } |
1163 | 1185 | ||
1164 | void __devinit smp_prepare_boot_cpu(void) | 1186 | /* Current gdt points %fs at the "master" per-cpu area: after this, |
1187 | * it's on the real one. */ | ||
1188 | static inline void switch_to_new_gdt(void) | ||
1165 | { | 1189 | { |
1166 | cpu_set(smp_processor_id(), cpu_online_map); | 1190 | load_gdt(&per_cpu(cpu_gdt_descr, smp_processor_id())); |
1167 | cpu_set(smp_processor_id(), cpu_callout_map); | 1191 | asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory"); |
1168 | cpu_set(smp_processor_id(), cpu_present_map); | 1192 | } |
1169 | cpu_set(smp_processor_id(), cpu_possible_map); | 1193 | |
1170 | per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; | 1194 | void __init smp_prepare_boot_cpu(void) |
1195 | { | ||
1196 | unsigned int cpu = smp_processor_id(); | ||
1197 | |||
1198 | init_gdt(cpu, current); | ||
1199 | switch_to_new_gdt(); | ||
1200 | |||
1201 | cpu_set(cpu, cpu_online_map); | ||
1202 | cpu_set(cpu, cpu_callout_map); | ||
1203 | cpu_set(cpu, cpu_present_map); | ||
1204 | cpu_set(cpu, cpu_possible_map); | ||
1205 | __get_cpu_var(cpu_state) = CPU_ONLINE; | ||
1171 | } | 1206 | } |
1172 | 1207 | ||
1173 | #ifdef CONFIG_HOTPLUG_CPU | 1208 | #ifdef CONFIG_HOTPLUG_CPU |