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