[coreboot] r837 - coreboot-v3/arch/x86/amd/model_fxx

svn at coreboot.org svn at coreboot.org
Thu Aug 28 04:37:29 CEST 2008


Author: rminnich
Date: 2008-08-28 04:37:29 +0200 (Thu, 28 Aug 2008)
New Revision: 837

Added:
   coreboot-v3/arch/x86/amd/model_fxx/dualcore.c
Log:
This code is not in a working state but I want to get it into the repo
since the box it is on is kinda old. 

I realize it is wrong but it is getting there. 

The k8 startup is a work of genius. I hope at some point it will be a 
work of genius that the rest of us can understand :-)

But it's very impressive code in how it works.

Discussions with AMD: we're in agreement that the structure of this code 
will change for the better, but it's helpful to have this audit trail of 
changes.

Signed-off-by: Ronald G. Minnich <rminnich at gmail.com>
Acked-by: Ronald G. Minnich <rminnich at gmail.com>



Added: coreboot-v3/arch/x86/amd/model_fxx/dualcore.c
===================================================================
--- coreboot-v3/arch/x86/amd/model_fxx/dualcore.c	                        (rev 0)
+++ coreboot-v3/arch/x86/amd/model_fxx/dualcore.c	2008-08-28 02:37:29 UTC (rev 837)
@@ -0,0 +1,180 @@
+/* 2004.12 yhlu add dual core support */
+#include <mainboard.h>
+#include <types.h>
+#include <lib.h>
+#include <console.h>
+#include <globalvars.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+#include <msr.h>
+#include <io.h>
+#include <cpu.h>
+#include <amd/k8/k8.h>
+#include <mc146818rtc.h>
+#include <spd.h>
+
+
+#ifndef SET_NB_CFG_54
+	#define SET_NB_CFG_54 1
+#endif
+
+/**
+ * Given a nodeid, return the count of the number of cores in that node. 
+ * @param nodeid The nodeid
+ * @returns The number of cores in that node. 
+ */
+unsigned int get_core_count(unsigned nodeid)
+{
+	u32 dword;
+	dword = pci_read_config32(PCI_BDF(0, 0x18+nodeid, 3), NORTHBRIDGE_CAP);
+	dword >>= NBCAP_CmpCap_SHIFT;
+	dword &= NBCAP_CmpCap_MASK;
+	return dword;
+}
+
+#if SET_NB_CFG_54 == 1
+static inline uint8_t set_apicid_cpuid_lo(void)
+{
+#if K8_REV_F_SUPPORT == 0
+        if(is_cpu_pre_e0()) return 0; // pre_e0 can not be set
+#endif
+
+        // set the NB_CFG[54]=1; why the OS will be happy with that ???
+        msr_t msr;
+        msr = rdmsr(NB_CFG_MSR);
+        msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
+        wrmsr(NB_CFG_MSR, msr);
+
+        return 1;
+}
+#else
+
+static inline void set_apicid_cpuid_lo(void) { }
+
+#endif
+
+static inline void real_start_other_core(unsigned nodeid)
+{
+	uint32_t dword;
+	// set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4 accesses and error logging to core0
+	dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 3), 0x44);
+	dword |= 1<<27; // NbMcaToMstCpuEn bit
+	pci_write_config32(PCI_DEV(0, 0x18+nodeid, 3), 0x44, dword);
+	// set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
+	dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 0), 0x68);
+	dword |= 1<<5;
+	pci_write_config32(PCI_DEV(0, 0x18+nodeid, 0), 0x68, dword);
+}
+
+//it is running on core0 of node0
+static inline void start_other_cores(void)
+{
+	unsigned nodes;
+	unsigned nodeid;
+
+        if(read_option(CMOS_VSTART_dual_core, CMOS_VLEN_dual_core, 0) != 0)  { // disable dual_core
+                return;
+        }
+
+        nodes = get_nodes();
+
+        for(nodeid=0; nodeid<nodes; nodeid++) {
+		if( get_core_num_in_bsp(nodeid) > 0) {
+			real_start_other_core(nodeid);
+		}
+	}
+
+}
+#if USE_DCACHE_RAM == 0
+static void do_k8_init_and_stop_secondaries(void)
+{
+	struct node_core_id id;
+	device_t dev;
+	unsigned apicid;
+	unsigned max_siblings;
+	msr_t msr;
+	
+	/* Skip this if there was a built in self test failure */
+
+	if (is_cpu_pre_e0()) {
+		id.nodeid = lapicid() & 0x7;
+		id.coreid = 0;
+	} else {
+		/* Which cpu are we on? */
+		id = get_node_core_id_x();
+
+		/* Set NB_CFG_MSR
+		 * Linux expect the core to be in the least signficant bits.
+		 */
+		msr = rdmsr(NB_CFG_MSR);
+		msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
+		wrmsr(NB_CFG_MSR, msr);
+	}
+
+	/* For now assume all cpus have the same number of siblings */
+	max_siblings = (cpuid_ecx(0x80000008) & 0xff) + 1;
+
+	/* Enable extended apic ids */
+	device_t dev_f0 = PCI_DEV(0, 0x18+id.nodeid, 0);
+	unsigned val = pci_read_config32(dev_f0, 0x68);
+	val |= (1 << 18) | (1 << 17);
+	pci_write_config32(dev_f0, 0x68, val);
+
+	/* Set the lapicid */
+        #if (ENABLE_APIC_EXT_ID == 1)
+                unsigned initial_apicid = get_initial_apicid();
+                #if LIFT_BSP_APIC_ID == 0
+                if( initial_apicid != 0 ) // other than bsp
+                #endif
+                {
+                                /* use initial apic id to lift it */
+                                uint32_t dword = lapic_read(LAPIC_ID);
+                                dword &= ~(0xff<<24);
+                                dword |= (((initial_apicid + APIC_ID_OFFSET) & 0xff)<<24);
+
+                                lapic_write(LAPIC_ID, dword);
+                }
+
+                #if LIFT_BSP_APIC_ID == 1
+                bsp_apicid += APIC_ID_OFFSET;
+                #endif
+
+        #endif
+
+
+	/* Remember the cpuid */
+	if (id.coreid == 0) {
+		dev = PCI_DEV(0, 0x18 + id.nodeid, 2);
+		pci_write_config32(dev, 0x9c, cpuid_eax(1));	
+	}
+	
+	/* Maybe call distinguish_cpu_resets only on the last core? */
+	distinguish_cpu_resets(id.nodeid);
+	if (!boot_cpu()) {
+		stop_this_cpu();
+	}
+}
+
+static void k8_init_and_stop_secondaries(void)
+{
+	/* This doesn't work with Cache As Ram because it messes with 
+	   the MTRR state, which breaks the init detection.
+	   do_k8_init_and_stop_secondaries should be usable by CAR code.
+	*/
+
+	int init_detected;
+
+	init_detected = early_mtrr_init_detected();
+	amd_early_mtrr_init();
+
+	enable_lapic();
+	init_timer();
+	if (init_detected) {
+		asm volatile ("jmp __cpu_reset");
+	}
+
+	do_k8_init_and_stop_secondaries();
+}
+
+#endif





More information about the coreboot mailing list