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