AMD Rev F support
[coreboot.git] / src / cpu / x86 / lapic / lapic_cpu_init.c
index 7f348790e5faaca18fec0667da213633aabb65b0..1adafc8d18baeffd94e82e2951b4d3fde6841929 100644 (file)
@@ -1,3 +1,8 @@
+/*
+       2005.12 yhlu add linuxbios_ram cross the vga font buffer handling
+       2005.12 yhlu add _RAMBASE above 1M support for SMP
+*/
+
 #include <cpu/x86/lapic.h>
 #include <delay.h>
 #include <string.h>
@@ -9,7 +14,6 @@
 #include <smp/spinlock.h>
 #include <cpu/cpu.h>
 
-
 #if CONFIG_SMP == 1
 
 /* This is a lot more paranoid now, since Linux can NOT handle
  * We actually handling that case by noting which cpus startup
  * and not telling anyone about the ones that dont.
  */ 
+static unsigned long get_valid_start_eip(unsigned long orig_start_eip)
+{
+       return (unsigned long)orig_start_eip & 0xffff; // 16 bit to avoid 0xa0000 
+}
+
+static void copy_secondary_start_to_1m_below(void) 
+{
+#if _RAMBASE >= 0x100000
+        extern char _secondary_start[];
+        extern char _secondary_start_end[];
+        unsigned long code_size;
+        unsigned long start_eip;
+
+        /* _secondary_start need to be masked 20 above bit, because 16 bit code in secondary.S
+                Also We need to copy the _secondary_start to the below 1M region
+        */
+        start_eip = get_valid_start_eip((unsigned long)_secondary_start);
+        code_size = (unsigned long)_secondary_start_end - (unsigned long)_secondary_start;
+
+        /* copy the _secondary_start to the ram below 1M*/
+        memcpy((unsigned char *)start_eip, (unsigned char *)_secondary_start, code_size);
+
+        printk_debug("start_eip=0x%08lx, offset=0x%08lx, code_size=0x%08lx\n", start_eip, ((unsigned long)_secondary_start - start_eip), code_size);
+#endif
+}
+
 static int lapic_start_cpu(unsigned long apicid)
 {
        int timeout;
@@ -87,9 +117,12 @@ static int lapic_start_cpu(unsigned long apicid)
                return 0;
        }
 
+#if _RAMBASE >= 0x100000
+       start_eip = get_valid_start_eip((unsigned long)_secondary_start);
+#else
        start_eip = (unsigned long)_secondary_start;
-       printk_spew("start_eip=0x%08lx\n", start_eip);
-       
+#endif
+
        num_starts = 2;
 
        /*
@@ -193,7 +226,25 @@ int start_cpu(device_t cpu)
        index = ++last_cpu_index;
        
        /* Find end of the new processors stack */
+#if (CONFIG_LB_MEM_TOPK>1024) && (_RAMBASE < 0x100000) && ((CONFIG_CONSOLE_VGA==1) || (CONFIG_PCI_ROM_RUN == 1))
+       if(index<1) { // only keep bsp on low 
+               stack_end = ((unsigned long)_estack) - (STACK_SIZE*index) - sizeof(struct cpu_info);
+       } else {
+               // for all APs, let use stack after pgtbl, 20480 is the pgtbl size for every cpu
+               stack_end = 0x100000+(20480 + STACK_SIZE)*CONFIG_MAX_CPUS - (STACK_SIZE*index);
+#if (0x100000+(20480 + STACK_SIZE)*CONFIG_MAX_CPU) > (CONFIG_LB_MEM_TOPK<<10)
+               #warning "We may need to increase CONFIG_LB_MEM_TOPK, it need to be more than (0x100000+(20480 + STACK_SIZE)*CONFIG_MAX_CPU)\n"
+#endif
+               if(stack_end > (CONFIG_LB_MEM_TOPK<<10)) {
+                       printk_debug("start_cpu: Please increase the CONFIG_LB_MEM_TOPK more than %dK\n", stack_end>>10);
+                       die("Can not go on\n");
+               }
+               stack_end -= sizeof(struct cpu_info);
+       }
+#else
        stack_end = ((unsigned long)_estack) - (STACK_SIZE*index) - sizeof(struct cpu_info);
+#endif
+
        
        /* Record the index and which cpu structure we are using */
        info = (struct cpu_info *)stack_end;
@@ -227,48 +278,51 @@ int start_cpu(device_t cpu)
 }
 
 /* C entry point of secondary cpus */
-
-// secondary_cpu_lock is used to serialize initialization of secondary CPUs
-// This can be used to avoid interleaved debugging messages.
-
-static spinlock_t secondary_cpu_lock = SPIN_LOCK_UNLOCKED;
-
 void secondary_cpu_init(void)
 {
        atomic_inc(&active_cpus);
-
 #if SERIAL_CPU_INIT == 1
-       spin_lock(&secondary_cpu_lock);
+  #if CONFIG_MAX_CPUS>2
+       spin_lock(&start_cpu_lock);
+  #endif
 #endif
-
        cpu_initialize();
-
 #if SERIAL_CPU_INIT == 1
-       spin_unlock(&secondary_cpu_lock);
+  #if CONFIG_MAX_CPUS>2
+       spin_unlock(&start_cpu_lock);
+  #endif
 #endif
 
        atomic_dec(&active_cpus);
        stop_this_cpu();
 }
 
-static void initialize_other_cpus(struct bus *cpu_bus)
+static void start_other_cpus(struct bus *cpu_bus, device_t bsp_cpu)
 {
-       int old_active_count, active_count;
        device_t cpu;
        /* Loop through the cpus once getting them started */
+
        for(cpu = cpu_bus->children; cpu ; cpu = cpu->sibling) {
                if (cpu->path.type != DEVICE_PATH_APIC) {
                        continue;
                }
+       #if SERIAL_CPU_INIT == 0
+               if(cpu==bsp_cpu) {
+                       continue; 
+               }
+       #endif
+
                if (!cpu->enabled) {
                        continue;
                }
+
                if (cpu->initialized) {
                        continue;
                }
+
                if (!start_cpu(cpu)) {
                        /* Record the error in cpu? */
-                       printk_err("CPU  %u would not start!\n",
+                       printk_err("CPU 0x%02x would not start!\n",
                                cpu->path.u.apic.apic_id);
                }
 #if SERIAL_CPU_INIT == 1
@@ -278,6 +332,12 @@ static void initialize_other_cpus(struct bus *cpu_bus)
 #endif
        }
 
+}
+
+static void wait_other_cpus_stop(struct bus *cpu_bus)
+{
+       device_t cpu;
+       int old_active_count, active_count;
        /* Now loop until the other cpus have finished initializing */
        old_active_count = 1;
        active_count = atomic_read(&active_cpus);
@@ -294,7 +354,7 @@ static void initialize_other_cpus(struct bus *cpu_bus)
                        continue;
                }
                if (!cpu->initialized) {
-                       printk_err("CPU %u did not initialize!\n", 
+                       printk_err("CPU 0x%02x did not initialize!\n", 
                                cpu->path.u.apic.apic_id);
 #warning "FIXME do I need a mainboard_cpu_fixup function?"
                }
@@ -306,6 +366,10 @@ static void initialize_other_cpus(struct bus *cpu_bus)
 #define initialize_other_cpus(root) do {} while(0)
 #endif /* CONFIG_SMP */
 
+#if WAIT_BEFORE_CPUS_INIT==0
+       #define cpus_ready_for_init() do {} while(0)
+#endif
+
 void initialize_cpus(struct bus *cpu_bus)
 {
        struct device_path cpu_path;
@@ -329,11 +393,32 @@ void initialize_cpus(struct bus *cpu_bus)
        
        /* Find the device structure for the boot cpu */
        info->cpu = alloc_find_dev(cpu_bus, &cpu_path);
+
+#if CONFIG_SMP == 1
+       copy_secondary_start_to_1m_below(); // why here? In case some day we can start core1 in amd_sibling_init
+#endif
        
-       /* Initialize the bootstrap processor */
-       cpu_initialize();
+        cpus_ready_for_init(); 
+
+#if CONFIG_SMP == 1
+       #if SERIAL_CPU_INIT == 0
+       /* start all aps at first, so we can init ECC all together */
+        start_other_cpus(cpu_bus, info->cpu);
+       #endif
+#endif
+
+        /* Initialize the bootstrap processor */
+        cpu_initialize();
+
+
+#if CONFIG_SMP == 1
+        #if SERIAL_CPU_INIT == 1
+        start_other_cpus(cpu_bus, info->cpu);
+        #endif
+
+       /* Now wait the rest of the cpus stop*/
+       wait_other_cpus_stop(cpu_bus);
+#endif
 
-       /* Now initialize the rest of the cpus */
-       initialize_other_cpus(cpu_bus);
 }