1 /* 2004.12 yhlu add dual core support */
5 #define SET_NB_CFG_54 1
8 #include "cpu/amd/dualcore/dualcore_id.c"
10 static inline unsigned get_core_num_in_bsp(unsigned nodeid)
13 dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 3), 0xe8);
19 #if SET_NB_CFG_54 == 1
20 static inline uint8_t set_apicid_cpuid_lo(void)
22 #if CONFIG_K8_REV_F_SUPPORT == 0
23 if(is_cpu_pre_e0()) return 0; // pre_e0 can not be set
26 // set the NB_CFG[54]=1; why the OS will be happy with that ???
28 msr = rdmsr(NB_CFG_MSR);
29 msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
30 wrmsr(NB_CFG_MSR, msr);
36 static inline void set_apicid_cpuid_lo(void) { }
40 static inline void real_start_other_core(unsigned nodeid)
43 // set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4 accesses and error logging to core0
44 dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 3), 0x44);
45 dword |= 1<<27; // NbMcaToMstCpuEn bit
46 pci_write_config32(PCI_DEV(0, 0x18+nodeid, 3), 0x44, dword);
47 // set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
48 dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 0), 0x68);
50 pci_write_config32(PCI_DEV(0, 0x18+nodeid, 0), 0x68, dword);
53 //it is running on core0 of node0
54 static inline void start_other_cores(void)
59 if (CONFIG_HAVE_OPTION_TABLE &&
60 read_option(CMOS_VSTART_dual_core, CMOS_VLEN_dual_core, 0) != 0) {
61 return; // disable dual_core
66 for(nodeid=0; nodeid<nodes; nodeid++) {
67 if( get_core_num_in_bsp(nodeid) > 0) {
68 real_start_other_core(nodeid);
73 #if CONFIG_USE_DCACHE_RAM == 0
74 static void do_k8_init_and_stop_secondaries(void)
76 struct node_core_id id;
79 unsigned max_siblings;
82 /* Skip this if there was a built in self test failure */
84 if (is_cpu_pre_e0()) {
85 id.nodeid = lapicid() & 0x7;
88 /* Which cpu are we on? */
89 id = get_node_core_id_x();
92 * Linux expect the core to be in the least signficant bits.
94 msr = rdmsr(NB_CFG_MSR);
95 msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
96 wrmsr(NB_CFG_MSR, msr);
99 /* For now assume all cpus have the same number of siblings */
100 max_siblings = (cpuid_ecx(0x80000008) & 0xff) + 1;
102 /* Enable extended apic ids */
103 device_t dev_f0 = PCI_DEV(0, 0x18+id.nodeid, 0);
104 unsigned val = pci_read_config32(dev_f0, 0x68);
105 val |= (1 << 18) | (1 << 17);
106 pci_write_config32(dev_f0, 0x68, val);
108 /* Set the lapicid */
109 #if (CONFIG_ENABLE_APIC_EXT_ID == 1)
110 unsigned initial_apicid = get_initial_apicid();
111 #if CONFIG_LIFT_BSP_APIC_ID == 0
112 if( initial_apicid != 0 ) // other than bsp
115 /* use initial apic id to lift it */
116 uint32_t dword = lapic_read(LAPIC_ID);
117 dword &= ~(0xff<<24);
118 dword |= (((initial_apicid + CONFIG_APIC_ID_OFFSET) & 0xff)<<24);
120 lapic_write(LAPIC_ID, dword);
123 #if CONFIG_LIFT_BSP_APIC_ID == 1
124 bsp_apicid += CONFIG_APIC_ID_OFFSET;
130 /* Remember the cpuid */
131 if (id.coreid == 0) {
132 dev = PCI_DEV(0, 0x18 + id.nodeid, 2);
133 pci_write_config32(dev, 0x9c, cpuid_eax(1));
136 /* Maybe call distinguish_cpu_resets only on the last core? */
137 distinguish_cpu_resets(id.nodeid);
143 static void k8_init_and_stop_secondaries(void)
145 /* This doesn't work with Cache As Ram because it messes with
146 the MTRR state, which breaks the init detection.
147 do_k8_init_and_stop_secondaries should be usable by CAR code.
152 init_detected = early_mtrr_init_detected();
153 amd_early_mtrr_init();
158 asm volatile ("jmp __cpu_reset");
161 do_k8_init_and_stop_secondaries();