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