23edfa08ae67222224566f994a796deafb175d6a
[coreboot.git] / src / cpu / amd / model_fxx / init_cpus.c
1 //it takes the CONFIG_ENABLE_APIC_EXT_ID and CONFIG_APIC_ID_OFFSET and CONFIG_LIFT_BSP_APIC_ID
2 #ifndef SET_FIDVID
3 #if CONFIG_K8_REV_F_SUPPORT == 0
4         #define SET_FIDVID 0
5 #else
6                 // for rev F, need to set FID to max
7         #define SET_FIDVID 1
8 #endif
9
10 #endif
11
12 #ifndef SET_FIDVID_CORE0_ONLY
13         /* MSR FIDVID_CTL and FIDVID_STATUS are shared by cores, so may don't need to do twice */
14         #define SET_FIDVID_CORE0_ONLY 1
15 #endif
16
17 typedef void (*process_ap_t) (u32 apicid, void *gp);
18
19 //core_range = 0 : all cores
20 //core range = 1 : core 0 only
21 //core range = 2 : cores other than core0
22
23 static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap,
24                         void *gp)
25 {
26         // here assume the OS don't change our apicid
27         u32 ap_apicid;
28
29         u32 nodes;
30         u32 siblings = 0;
31         u32 disable_siblings;
32         u32 e0_later_single_core;
33         u32 nb_cfg_54;
34         int i, j;
35
36         /* get_nodes define in in_coherent_ht.c */
37         nodes = get_nodes();
38
39         if (!CONFIG_LOGICAL_CPUS ||
40             read_option(CMOS_VSTART_multi_core, CMOS_VLEN_multi_core, 0) != 0) {        // 0 means multi core
41                 disable_siblings = 1;
42         } else {
43                 disable_siblings = 0;
44         }
45
46         /* here I assume that all node are same stepping, otherwise we can use use nb_cfg_54 from bsp for all nodes */
47         nb_cfg_54 = read_nb_cfg_54();
48
49         for (i = 0; i < nodes; i++) {
50                 e0_later_single_core = 0;
51                 j = ((pci_read_config32(PCI_DEV(0, 0x18 + i, 3), 0xe8) >> 12) &
52                      3);
53                 if (nb_cfg_54) {
54                         if (j == 0) {   // if it is single core, we need to increase siblings for apic calculation
55 #if CONFIG_K8_REV_F_SUPPORT == 0
56                                 e0_later_single_core = is_e0_later_in_bsp(i);   // single core
57 #else
58                                 e0_later_single_core = is_cpu_f0_in_bsp(i);     // We can read cpuid(1) from Func3
59 #endif
60                         }
61                         if (e0_later_single_core) {
62                                 j = 1;
63                         }
64                 }
65                 siblings = j;
66
67                 u32 jstart, jend;
68
69                 if (core_range == 2) {
70                         jstart = 1;
71                 } else {
72                         jstart = 0;
73                 }
74
75                 if (e0_later_single_core || disable_siblings
76                     || (core_range == 1)) {
77                         jend = 0;
78                 } else {
79                         jend = siblings;
80                 }
81
82                 for (j = jstart; j <= jend; j++) {
83                         ap_apicid =
84                             i * (nb_cfg_54 ? (siblings + 1) : 1) +
85                             j * (nb_cfg_54 ? 1 : 8);
86
87 #if (CONFIG_ENABLE_APIC_EXT_ID == 1)
88 #if CONFIG_LIFT_BSP_APIC_ID == 0
89                         if ((i != 0) || (j != 0))       /* except bsp */
90 #endif
91                                 ap_apicid += CONFIG_APIC_ID_OFFSET;
92 #endif
93
94                         if (ap_apicid == bsp_apicid)
95                                 continue;
96
97                         process_ap(ap_apicid, gp);
98
99                 }
100         }
101 }
102
103 static inline int lapic_remote_read(int apicid, int reg, u32 *pvalue)
104 {
105         int timeout;
106         u32 status;
107         int result;
108         lapic_wait_icr_idle();
109         lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
110         lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
111
112 /* Extra busy check compared to lapic.h */
113         timeout = 0;
114         do {
115                 status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
116         } while (status == LAPIC_ICR_BUSY && timeout++ < 1000);
117
118         timeout = 0;
119         do {
120                 status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
121         } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
122
123         result = -1;
124
125         if (status == LAPIC_ICR_RR_VALID) {
126                 *pvalue = lapic_read(LAPIC_RRR);
127                 result = 0;
128         }
129         return result;
130 }
131
132 #define LAPIC_MSG_REG 0x380
133
134 #if SET_FIDVID == 1
135 static void init_fidvid_ap(u32 bsp_apicid, u32 apicid);
136 #endif
137
138 static inline __attribute__ ((always_inline))
139 void print_apicid_nodeid_coreid(u32 apicid, struct node_core_id id,
140                                 const char *str)
141 {
142         printk(BIOS_DEBUG,
143                "%s --- { APICID = %02x NODEID = %02x COREID = %02x} ---\n", str,
144                apicid, id.nodeid, id.coreid);
145 }
146
147 static u32 wait_cpu_state(u32 apicid, u32 state)
148 {
149         u32 readback = 0;
150         u32 timeout = 1;
151         int loop = 2000000;
152         while (--loop > 0) {
153                 if (lapic_remote_read(apicid, LAPIC_MSG_REG, &readback) != 0)
154                         continue;
155                 if ((readback & 0xff) == state) {
156                         timeout = 0;
157                         break;  //target cpu is in stage started
158                 }
159         }
160         if (timeout) {
161                 if (readback) {
162                         timeout = readback;
163                 }
164         }
165
166         return timeout;
167 }
168
169 static void wait_ap_started(u32 ap_apicid, void *gp)
170 {
171         u32 timeout;
172         timeout = wait_cpu_state(ap_apicid, 0x33);      // started
173         printk(BIOS_DEBUG, "* AP %02x", ap_apicid);
174         if (timeout) {
175                 printk(BIOS_DEBUG, " timed out:%08x\n", timeout);
176         } else {
177                 printk(BIOS_DEBUG, "started\n");
178         }
179 }
180
181 void wait_all_aps_started(u32 bsp_apicid)
182 {
183         for_each_ap(bsp_apicid, 0, wait_ap_started, (void *)0);
184 }
185
186 void wait_all_other_cores_started(u32 bsp_apicid)
187 {
188         // all aps other than core0
189         printk(BIOS_DEBUG, "started ap apicid: ");
190         for_each_ap(bsp_apicid, 2, wait_ap_started, (void *)0);
191         printk(BIOS_DEBUG, "\n");
192 }
193
194 static void allow_all_aps_stop(u32 bsp_apicid)
195 {
196         // allow aps to stop
197
198         lapic_write(LAPIC_MSG_REG, (bsp_apicid << 24) | 0x44);
199 }
200
201 static void STOP_CAR_AND_CPU(void)
202 {
203         disable_cache_as_ram(); // inline
204         /* stop all cores except node0/core0 the bsp .... */
205         stop_this_cpu();
206 }
207
208 #if RAMINIT_SYSINFO == 1
209 static u32 init_cpus(u32 cpu_init_detectedx, struct sys_info *sysinfo)
210 #else
211 static u32 init_cpus(u32 cpu_init_detectedx)
212 #endif
213 {
214         u32 bsp_apicid = 0;
215         u32 apicid;
216         struct node_core_id id;
217
218         /*
219          * already set early mtrr in cache_as_ram.inc
220          */
221
222         /* that is from initial apicid, we need nodeid and coreid
223            later */
224         id = get_node_core_id_x();
225
226         /* NB_CFG MSR is shared between cores, so we need make sure
227            core0 is done at first --- use wait_all_core0_started  */
228         if (id.coreid == 0) {
229                 set_apicid_cpuid_lo();  /* only set it on core0 */
230 #if (CONFIG_ENABLE_APIC_EXT_ID == 1)
231                 enable_apic_ext_id(id.nodeid);
232 #endif
233         }
234
235         enable_lapic();
236         //      init_timer(); // We need TMICT to pass msg for FID/VID change
237
238 #if (CONFIG_ENABLE_APIC_EXT_ID == 1)
239         u32 initial_apicid = get_initial_apicid();
240
241 #if CONFIG_LIFT_BSP_APIC_ID == 0
242         if (initial_apicid != 0)        // other than bsp
243 #endif
244         {
245                 /* use initial apic id to lift it */
246                 u32 dword = lapic_read(LAPIC_ID);
247                 dword &= ~(0xff << 24);
248                 dword |=
249                     (((initial_apicid + CONFIG_APIC_ID_OFFSET) & 0xff) << 24);
250
251                 lapic_write(LAPIC_ID, dword);
252         }
253 #if CONFIG_LIFT_BSP_APIC_ID == 1
254         bsp_apicid += CONFIG_APIC_ID_OFFSET;
255 #endif
256
257 #endif
258
259         /* get the apicid, it may be lifted already */
260         apicid = lapicid();
261
262 #if 0
263         // show our apicid, nodeid, and coreid
264         if (id.coreid == 0) {
265                 if (id.nodeid != 0)     //all core0 except bsp
266                         print_apicid_nodeid_coreid(apicid, id, " core0: ");
267         } else {                //all other cores
268                 print_apicid_nodeid_coreid(apicid, id, " corex: ");
269         }
270 #endif
271
272         if (cpu_init_detectedx) {
273                 print_apicid_nodeid_coreid(apicid, id,
274                                            "\n\n\nINIT detected from ");
275                 printk(BIOS_DEBUG, "\nIssuing SOFT_RESET...\n");
276                 soft_reset();
277         }
278
279         if (id.coreid == 0) {
280                 distinguish_cpu_resets(id.nodeid);
281 //            start_other_core(id.nodeid); // start second core in first cpu, only allowed for nb_cfg_54 is not set
282         }
283         //here don't need to wait
284         lapic_write(LAPIC_MSG_REG, (apicid << 24) | 0x33);      // mark the cpu is started
285
286         if (apicid != bsp_apicid) {
287                 u32 timeout = 1;
288                 u32 loop = 100;
289
290 #if SET_FIDVID == 1
291 #if (CONFIG_LOGICAL_CPUS == 1) && (SET_FIDVID_CORE0_ONLY == 1)
292                 if (id.coreid == 0)     // only need set fid for core0
293 #endif
294                         init_fidvid_ap(bsp_apicid, apicid);
295 #endif
296
297                 // We need to stop the CACHE as RAM for this CPU, really?
298                 while (timeout && (loop-- > 0)) {
299                         timeout = wait_cpu_state(bsp_apicid, 0x44);
300                 }
301                 if (timeout) {
302                         printk(BIOS_DEBUG,
303                                "while waiting for BSP signal to STOP, timeout in ap %02x\n",
304                                apicid);
305                 }
306                 lapic_write(LAPIC_MSG_REG, (apicid << 24) | 0x44);      // bsp can not check it before stop_this_cpu
307                 set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
308 #if CONFIG_MEM_TRAIN_SEQ == 1
309                 train_ram_on_node(id.nodeid, id.coreid, sysinfo,
310                                   (unsigned)STOP_CAR_AND_CPU);
311 #endif
312
313                 STOP_CAR_AND_CPU();
314         }
315
316         return bsp_apicid;
317 }
318
319 static u32 is_core0_started(u32 nodeid)
320 {
321         u32 htic;
322         device_t device;
323         device = PCI_DEV(0, 0x18 + nodeid, 0);
324         htic = pci_read_config32(device, HT_INIT_CONTROL);
325         htic &= HTIC_INIT_Detect;
326         return htic;
327 }
328
329 static void wait_all_core0_started(void)
330 {
331         /* When core0 is started, it will distingush_cpu_resets
332          * So wait for that to finish */
333         u32 i;
334         u32 nodes = get_nodes();
335
336         printk(BIOS_DEBUG, "core0 started: ");
337         for (i = 1; i < nodes; i++) {   // skip bsp, because it is running on bsp
338                 while (!is_core0_started(i)) {
339                 }
340                 printk(BIOS_DEBUG, " %02x", i);
341         }
342         printk(BIOS_DEBUG, "\n");
343 }