aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/amd/dualcore/dualcore.c
blob: 68b595a539e67e85a31f8ca7edf4501127c4f5a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* 2004.12 yhlu add dual core support */


#ifndef SET_NB_CFG_54
	#define SET_NB_CFG_54 1
#endif

#include "cpu/amd/dualcore/dualcore_id.c"

static inline unsigned get_core_num_in_bsp(unsigned nodeid)
{
	uint32_t dword;
	dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 3), 0xe8);
	dword >>= 12;
	dword &= 3;
	return dword;
}

#if SET_NB_CFG_54 == 1
static inline uint8_t set_apicid_cpuid_lo(void)
{
#if CONFIG_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 (CONFIG_HAVE_OPTION_TABLE &&
	    read_option(CMOS_VSTART_multi_core, CMOS_VLEN_multi_core, 0) != 0)  {
		return; // disable multi_core
	}

        nodes = get_nodes();

        for(nodeid=0; nodeid<nodes; nodeid++) {
		if( get_core_num_in_bsp(nodeid) > 0) {
			real_start_other_core(nodeid);
		}
	}

}
#if CONFIG_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 (CONFIG_ENABLE_APIC_EXT_ID == 1)
                unsigned initial_apicid = get_initial_apicid();
                #if CONFIG_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 + CONFIG_APIC_ID_OFFSET) & 0xff)<<24);

                                lapic_write(LAPIC_ID, dword);
                }

                #if CONFIG_LIFT_BSP_APIC_ID == 1
                bsp_apicid += CONFIG_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