aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2006-12-06 20:14:02 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-06 20:14:02 -0500
commit62111195800d80c66cdc69063ea3145878c99fbf (patch)
tree35bc9792b3ac232e70e106ff2f4c0193c3bb72ff
parent9ca36101a8d74704d78f10910f89d62de96f9dc8 (diff)
[PATCH] i386: Initialize the per-CPU data area
When a CPU is brought up, a PDA and GDT are allocated for it. The GDT's __KERNEL_PDA entry is pointed to the allocated PDA memory, so that all references using this segment descriptor will refer to the PDA. This patch rearranges CPU initialization a bit, so that the GDT/PDA are set up as early as possible in cpu_init(). Also for secondary CPUs, GDT+PDA are preallocated and initialized so all the secondary CPU needs to do is set up the ldt and load %gs. This will be important once smp_processor_id() and current use the PDA. In all cases, the PDA is set up in head.S, before a CPU starts running C code, so the PDA is always available. Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Chuck Ebbert <76306.1226@compuserve.com> Cc: Zachary Amsden <zach@vmware.com> Cc: Jan Beulich <jbeulich@novell.com> Cc: Andi Kleen <ak@suse.de> Cc: James Bottomley <James.Bottomley@SteelEye.com> Cc: Matt Tolentino <matthew.e.tolentino@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org>
-rw-r--r--arch/i386/kernel/cpu/common.c177
-rw-r--r--arch/i386/kernel/smpboot.c28
-rw-r--r--arch/i386/mach-voyager/voyager_smp.c14
-rw-r--r--include/asm-i386/processor.h3
4 files changed, 172 insertions, 50 deletions
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 5532fc4e1bf0..2534e25ed745 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -18,12 +18,16 @@
18#include <asm/apic.h> 18#include <asm/apic.h>
19#include <mach_apic.h> 19#include <mach_apic.h>
20#endif 20#endif
21#include <asm/pda.h>
21 22
22#include "cpu.h" 23#include "cpu.h"
23 24
24DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); 25DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
25EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); 26EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
26 27
28struct i386_pda *_cpu_pda[NR_CPUS] __read_mostly;
29EXPORT_SYMBOL(_cpu_pda);
30
27static int cachesize_override __cpuinitdata = -1; 31static int cachesize_override __cpuinitdata = -1;
28static int disable_x86_fxsr __cpuinitdata; 32static int disable_x86_fxsr __cpuinitdata;
29static int disable_x86_serial_nr __cpuinitdata = 1; 33static int disable_x86_serial_nr __cpuinitdata = 1;
@@ -588,41 +592,16 @@ void __init early_cpu_init(void)
588 disable_pse = 1; 592 disable_pse = 1;
589#endif 593#endif
590} 594}
591/* 595
592 * cpu_init() initializes state that is per-CPU. Some data is already 596__cpuinit int alloc_gdt(int cpu)
593 * initialized (naturally) in the bootstrap process, such as the GDT
594 * and IDT. We reload them nevertheless, this function acts as a
595 * 'CPU state barrier', nothing should get across.
596 */
597void __cpuinit cpu_init(void)
598{ 597{
599 int cpu = smp_processor_id();
600 struct tss_struct * t = &per_cpu(init_tss, cpu);
601 struct thread_struct *thread = &current->thread;
602 struct desc_struct *gdt;
603 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); 598 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
599 struct desc_struct *gdt;
600 struct i386_pda *pda;
604 601
605 if (cpu_test_and_set(cpu, cpu_initialized)) { 602 gdt = (struct desc_struct *)cpu_gdt_descr->address;
606 printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); 603 pda = cpu_pda(cpu);
607 for (;;) local_irq_enable();
608 }
609 printk(KERN_INFO "Initializing CPU#%d\n", cpu);
610 604
611 if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
612 clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
613 if (tsc_disable && cpu_has_tsc) {
614 printk(KERN_NOTICE "Disabling TSC...\n");
615 /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
616 clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
617 set_in_cr4(X86_CR4_TSD);
618 }
619
620 /* The CPU hotplug case */
621 if (cpu_gdt_descr->address) {
622 gdt = (struct desc_struct *)cpu_gdt_descr->address;
623 memset(gdt, 0, PAGE_SIZE);
624 goto old_gdt;
625 }
626 /* 605 /*
627 * This is a horrible hack to allocate the GDT. The problem 606 * This is a horrible hack to allocate the GDT. The problem
628 * is that cpu_init() is called really early for the boot CPU 607 * is that cpu_init() is called really early for the boot CPU
@@ -630,36 +609,117 @@ void __cpuinit cpu_init(void)
630 * CPUs, when bootmem will have gone away 609 * CPUs, when bootmem will have gone away
631 */ 610 */
632 if (NODE_DATA(0)->bdata->node_bootmem_map) { 611 if (NODE_DATA(0)->bdata->node_bootmem_map) {
633 gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE); 612 BUG_ON(gdt != NULL || pda != NULL);
634 /* alloc_bootmem_pages panics on failure, so no check */ 613
614 gdt = alloc_bootmem_pages(PAGE_SIZE);
615 pda = alloc_bootmem(sizeof(*pda));
616 /* alloc_bootmem(_pages) panics on failure, so no check */
617
635 memset(gdt, 0, PAGE_SIZE); 618 memset(gdt, 0, PAGE_SIZE);
619 memset(pda, 0, sizeof(*pda));
636 } else { 620 } else {
637 gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); 621 /* GDT and PDA might already have been allocated if
638 if (unlikely(!gdt)) { 622 this is a CPU hotplug re-insertion. */
639 printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu); 623 if (gdt == NULL)
640 for (;;) 624 gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
641 local_irq_enable(); 625
626 if (pda == NULL)
627 pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu));
628
629 if (unlikely(!gdt || !pda)) {
630 free_pages((unsigned long)gdt, 0);
631 kfree(pda);
632 return 0;
642 } 633 }
643 } 634 }
644old_gdt: 635
636 cpu_gdt_descr->address = (unsigned long)gdt;
637 cpu_pda(cpu) = pda;
638
639 return 1;
640}
641
642/* Initial PDA used by boot CPU */
643struct i386_pda boot_pda = {
644 ._pda = &boot_pda,
645};
646
647/* Initialize the CPU's GDT and PDA. The boot CPU does this for
648 itself, but secondaries find this done for them. */
649__cpuinit int init_gdt(int cpu, struct task_struct *idle)
650{
651 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
652 struct desc_struct *gdt;
653 struct i386_pda *pda;
654
655 /* For non-boot CPUs, the GDT and PDA should already have been
656 allocated. */
657 if (!alloc_gdt(cpu)) {
658 printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu);
659 return 0;
660 }
661
662 gdt = (struct desc_struct *)cpu_gdt_descr->address;
663 pda = cpu_pda(cpu);
664
665 BUG_ON(gdt == NULL || pda == NULL);
666
645 /* 667 /*
646 * Initialize the per-CPU GDT with the boot GDT, 668 * Initialize the per-CPU GDT with the boot GDT,
647 * and set up the GDT descriptor: 669 * and set up the GDT descriptor:
648 */ 670 */
649 memcpy(gdt, cpu_gdt_table, GDT_SIZE); 671 memcpy(gdt, cpu_gdt_table, GDT_SIZE);
650 cpu_gdt_descr->size = GDT_SIZE - 1; 672 cpu_gdt_descr->size = GDT_SIZE - 1;
651 cpu_gdt_descr->address = (unsigned long)gdt;
652 673
674 pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a,
675 (u32 *)&gdt[GDT_ENTRY_PDA].b,
676 (unsigned long)pda, sizeof(*pda) - 1,
677 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */
678
679 memset(pda, 0, sizeof(*pda));
680 pda->_pda = pda;
681
682 return 1;
683}
684
685/* Common CPU init for both boot and secondary CPUs */
686static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
687{
688 struct tss_struct * t = &per_cpu(init_tss, cpu);
689 struct thread_struct *thread = &curr->thread;
690 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
691
692 /* Reinit these anyway, even if they've already been done (on
693 the boot CPU, this will transition from the boot gdt+pda to
694 the real ones). */
653 load_gdt(cpu_gdt_descr); 695 load_gdt(cpu_gdt_descr);
696
697 if (cpu_test_and_set(cpu, cpu_initialized)) {
698 printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
699 for (;;) local_irq_enable();
700 }
701
702 printk(KERN_INFO "Initializing CPU#%d\n", cpu);
703
704 if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
705 clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
706 if (tsc_disable && cpu_has_tsc) {
707 printk(KERN_NOTICE "Disabling TSC...\n");
708 /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
709 clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
710 set_in_cr4(X86_CR4_TSD);
711 }
712
654 load_idt(&idt_descr); 713 load_idt(&idt_descr);
655 714
656 /* 715 /*
657 * Set up and load the per-CPU TSS and LDT 716 * Set up and load the per-CPU TSS and LDT
658 */ 717 */
659 atomic_inc(&init_mm.mm_count); 718 atomic_inc(&init_mm.mm_count);
660 current->active_mm = &init_mm; 719 curr->active_mm = &init_mm;
661 BUG_ON(current->mm); 720 if (curr->mm)
662 enter_lazy_tlb(&init_mm, current); 721 BUG();
722 enter_lazy_tlb(&init_mm, curr);
663 723
664 load_esp0(t, thread); 724 load_esp0(t, thread);
665 set_tss_desc(cpu,t); 725 set_tss_desc(cpu,t);
@@ -690,6 +750,37 @@ old_gdt:
690 mxcsr_feature_mask_init(); 750 mxcsr_feature_mask_init();
691} 751}
692 752
753/* Entrypoint to initialize secondary CPU */
754void __cpuinit secondary_cpu_init(void)
755{
756 int cpu = smp_processor_id();
757 struct task_struct *curr = current;
758
759 _cpu_init(cpu, curr);
760}
761
762/*
763 * cpu_init() initializes state that is per-CPU. Some data is already
764 * initialized (naturally) in the bootstrap process, such as the GDT
765 * and IDT. We reload them nevertheless, this function acts as a
766 * 'CPU state barrier', nothing should get across.
767 */
768void __cpuinit cpu_init(void)
769{
770 int cpu = smp_processor_id();
771 struct task_struct *curr = current;
772
773 /* Set up the real GDT and PDA, so we can transition from the
774 boot versions. */
775 if (!init_gdt(cpu, curr)) {
776 /* failed to allocate something; not much we can do... */
777 for (;;)
778 local_irq_enable();
779 }
780
781 _cpu_init(cpu, curr);
782}
783
693#ifdef CONFIG_HOTPLUG_CPU 784#ifdef CONFIG_HOTPLUG_CPU
694void __cpuinit cpu_uninit(void) 785void __cpuinit cpu_uninit(void)
695{ 786{
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 4bb8b77cd65b..095636620fa2 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -52,6 +52,7 @@
52#include <asm/desc.h> 52#include <asm/desc.h>
53#include <asm/arch_hooks.h> 53#include <asm/arch_hooks.h>
54#include <asm/nmi.h> 54#include <asm/nmi.h>
55#include <asm/pda.h>
55 56
56#include <mach_apic.h> 57#include <mach_apic.h>
57#include <mach_wakecpu.h> 58#include <mach_wakecpu.h>
@@ -536,11 +537,11 @@ set_cpu_sibling_map(int cpu)
536static void __devinit start_secondary(void *unused) 537static void __devinit start_secondary(void *unused)
537{ 538{
538 /* 539 /*
539 * Dont put anything before smp_callin(), SMP 540 * Don't put *anything* before secondary_cpu_init(), SMP
540 * booting is too fragile that we want to limit the 541 * booting is too fragile that we want to limit the
541 * things done here to the most necessary things. 542 * things done here to the most necessary things.
542 */ 543 */
543 cpu_init(); 544 secondary_cpu_init();
544 preempt_disable(); 545 preempt_disable();
545 smp_callin(); 546 smp_callin();
546 while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) 547 while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
@@ -599,13 +600,16 @@ void __devinit initialize_secondary(void)
599 "movl %0,%%esp\n\t" 600 "movl %0,%%esp\n\t"
600 "jmp *%1" 601 "jmp *%1"
601 : 602 :
602 :"r" (current->thread.esp),"r" (current->thread.eip)); 603 :"m" (current->thread.esp),"m" (current->thread.eip));
603} 604}
604 605
606/* Static state in head.S used to set up a CPU */
605extern struct { 607extern struct {
606 void * esp; 608 void * esp;
607 unsigned short ss; 609 unsigned short ss;
608} stack_start; 610} stack_start;
611extern struct i386_pda *start_pda;
612extern struct Xgt_desc_struct cpu_gdt_descr;
609 613
610#ifdef CONFIG_NUMA 614#ifdef CONFIG_NUMA
611 615
@@ -936,9 +940,6 @@ static int __devinit do_boot_cpu(int apicid, int cpu)
936 unsigned long start_eip; 940 unsigned long start_eip;
937 unsigned short nmi_high = 0, nmi_low = 0; 941 unsigned short nmi_high = 0, nmi_low = 0;
938 942
939 ++cpucount;
940 alternatives_smp_switch(1);
941
942 /* 943 /*
943 * We can't use kernel_thread since we must avoid to 944 * We can't use kernel_thread since we must avoid to
944 * reschedule the child. 945 * reschedule the child.
@@ -946,15 +947,30 @@ static int __devinit do_boot_cpu(int apicid, int cpu)
946 idle = alloc_idle_task(cpu); 947 idle = alloc_idle_task(cpu);
947 if (IS_ERR(idle)) 948 if (IS_ERR(idle))
948 panic("failed fork for CPU %d", cpu); 949 panic("failed fork for CPU %d", cpu);
950
951 /* Pre-allocate and initialize the CPU's GDT and PDA so it
952 doesn't have to do any memory allocation during the
953 delicate CPU-bringup phase. */
954 if (!init_gdt(cpu, idle)) {
955 printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
956 return -1; /* ? */
957 }
958
949 idle->thread.eip = (unsigned long) start_secondary; 959 idle->thread.eip = (unsigned long) start_secondary;
950 /* start_eip had better be page-aligned! */ 960 /* start_eip had better be page-aligned! */
951 start_eip = setup_trampoline(); 961 start_eip = setup_trampoline();
952 962
963 ++cpucount;
964 alternatives_smp_switch(1);
965
953 /* So we see what's up */ 966 /* So we see what's up */
954 printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); 967 printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
955 /* Stack for startup_32 can be just as for start_secondary onwards */ 968 /* Stack for startup_32 can be just as for start_secondary onwards */
956 stack_start.esp = (void *) idle->thread.esp; 969 stack_start.esp = (void *) idle->thread.esp;
957 970
971 start_pda = cpu_pda(cpu);
972 cpu_gdt_descr = per_cpu(cpu_gdt_descr, cpu);
973
958 irq_ctx_init(cpu); 974 irq_ctx_init(cpu);
959 975
960 x86_cpu_to_apicid[cpu] = apicid; 976 x86_cpu_to_apicid[cpu] = apicid;
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index f3fea2ad50fe..55428e656a3f 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -28,6 +28,7 @@
28#include <asm/pgalloc.h> 28#include <asm/pgalloc.h>
29#include <asm/tlbflush.h> 29#include <asm/tlbflush.h>
30#include <asm/arch_hooks.h> 30#include <asm/arch_hooks.h>
31#include <asm/pda.h>
31 32
32/* TLB state -- visible externally, indexed physically */ 33/* TLB state -- visible externally, indexed physically */
33DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 }; 34DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 };
@@ -422,6 +423,7 @@ find_smp_config(void)
422 VOYAGER_SUS_IN_CONTROL_PORT); 423 VOYAGER_SUS_IN_CONTROL_PORT);
423 424
424 current_thread_info()->cpu = boot_cpu_id; 425 current_thread_info()->cpu = boot_cpu_id;
426 write_pda(cpu_number, boot_cpu_id);
425} 427}
426 428
427/* 429/*
@@ -458,7 +460,7 @@ start_secondary(void *unused)
458 /* external functions not defined in the headers */ 460 /* external functions not defined in the headers */
459 extern void calibrate_delay(void); 461 extern void calibrate_delay(void);
460 462
461 cpu_init(); 463 secondary_cpu_init();
462 464
463 /* OK, we're in the routine */ 465 /* OK, we're in the routine */
464 ack_CPI(VIC_CPU_BOOT_CPI); 466 ack_CPI(VIC_CPU_BOOT_CPI);
@@ -578,6 +580,15 @@ do_boot_cpu(__u8 cpu)
578 /* init_tasks (in sched.c) is indexed logically */ 580 /* init_tasks (in sched.c) is indexed logically */
579 stack_start.esp = (void *) idle->thread.esp; 581 stack_start.esp = (void *) idle->thread.esp;
580 582
583 /* Pre-allocate and initialize the CPU's GDT and PDA so it
584 doesn't have to do any memory allocation during the
585 delicate CPU-bringup phase. */
586 if (!init_gdt(cpu, idle)) {
587 printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
588 cpucount--;
589 return;
590 }
591
581 irq_ctx_init(cpu); 592 irq_ctx_init(cpu);
582 593
583 /* Note: Don't modify initial ss override */ 594 /* Note: Don't modify initial ss override */
@@ -1963,4 +1974,5 @@ void __init
1963smp_setup_processor_id(void) 1974smp_setup_processor_id(void)
1964{ 1975{
1965 current_thread_info()->cpu = hard_smp_processor_id(); 1976 current_thread_info()->cpu = hard_smp_processor_id();
1977 write_pda(cpu_number, hard_smp_processor_id());
1966} 1978}
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index e0ddca94d50c..a9f2041c7c87 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -727,4 +727,7 @@ extern unsigned long boot_option_idle_override;
727extern void enable_sep_cpu(void); 727extern void enable_sep_cpu(void);
728extern int sysenter_setup(void); 728extern int sysenter_setup(void);
729 729
730extern int init_gdt(int cpu, struct task_struct *idle);
731extern void secondary_cpu_init(void);
732
730#endif /* __ASM_I386_PROCESSOR_H */ 733#endif /* __ASM_I386_PROCESSOR_H */