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