aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/smpboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/smpboot.c')
-rw-r--r--arch/i386/kernel/smpboot.c59
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)
440void __devinit initialize_secondary(void) 440void __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. */
787static __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 */
808extern struct Xgt_desc_struct early_gdt_descr;
809
790static int __cpuinit do_boot_cpu(int apicid, int cpu) 810static 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
1164void __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. */
1188static 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; 1194void __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