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