- cpu/smp detection code improved
[opensuse:hwinfo.git] / src / hd / cpu.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "hd.h"
6 #include "hd_int.h"
7 #include "cpu.h"
8
9 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
10  * cpu info
11  *
12  * Note: on other architectures, entries differ (cf. Alpha)!!!
13  *
14  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
15  */
16
17
18 static void dump_cpu_data(hd_data_t *hd_data);
19
20 void hd_scan_cpu(hd_data_t *hd_data)
21 {
22   hd_t *hd;
23   unsigned cpus = 0;
24   cpu_info_t *ct;
25   str_list_t *sl;
26
27 #ifdef __i386__
28   char model_id[80], vendor_id[80], features[0x100];
29   unsigned bogo, mhz, cache, family, model, stepping;
30   char *t0, *t;
31 #endif
32
33 #ifdef __ia64__
34   char model_id[80], vendor_id[80], features[0x100];
35   unsigned mhz, stepping;
36   char *t0, *t;
37 #endif
38
39 #ifdef __alpha__
40   char model_id[80], system_id[80], serial_number[80], platform[80];
41   unsigned cpu_variation, cpu_revision, u, hz;
42   cpu_info_t *ct1;
43 #endif
44
45 #ifdef __PPC__
46   char model_id[80], vendor_id[80], motherboard[80];
47   unsigned bogo, mhz, cache, family, model, stepping;
48 #endif
49
50 #ifdef __sparc__
51   char cpu_id[80], fpu_id[80], promlib[80], prom[80], type[80], mmu[80];
52   unsigned u, bogo, cpus_active;
53 #endif
54
55 #ifdef __s390__
56   char vendor_id[80];
57   unsigned bogo;
58   unsigned u0, u1, u2, u3;
59 #endif
60
61   if(!hd_probe_feature(hd_data, pr_cpu)) return;
62
63   hd_data->module = mod_cpu;
64
65   /* some clean-up */
66   remove_hd_entries(hd_data);
67   hd_data->cpu = NULL;
68
69   PROGRESS(1, 0, "cpuinfo");
70
71   hd_data->cpu = read_file(PROC_CPUINFO, 0, 0);
72   if((hd_data->debug & HD_DEB_CPU)) dump_cpu_data(hd_data);
73   if(!hd_data->cpu) return;
74
75 #ifdef __alpha__
76   *model_id = *system_id = *serial_number = *platform = 0;
77   cpu_variation = cpu_revision = hz = 0;
78
79   for(sl = hd_data->cpu; sl; sl = sl->next) {
80     if(sscanf(sl->str, "cpu model : %79[^\n]", model_id) == 1) continue;
81     if(sscanf(sl->str, "system type : %79[^\n]", system_id) == 1) continue;
82     if(sscanf(sl->str, "cpu variation : %u", &cpu_variation) == 1) continue;
83     if(sscanf(sl->str, "cpu revision : %u", &cpu_revision) == 1) continue;
84     if(sscanf(sl->str, "system serial number : %79[^\n]", serial_number) == 1) continue;
85     if(sscanf(sl->str, "cpus detected : %u", &cpus) == 1) continue;
86     if(sscanf(sl->str, "cycle frequency [Hz] : %u", &hz) == 1) continue;
87     if(sscanf(sl->str, "system variation : %79[^\n]", platform) == 1) continue;
88   }
89
90   if(*model_id || *system_id) { /* at least one of those */
91     ct = new_mem(sizeof *ct);
92     ct->architecture = arch_alpha;
93     if(model_id) ct->model_name = new_str(model_id);
94     if(system_id) ct->vend_name = new_str(system_id);
95     if(strncmp(serial_number, "MILO", 4) == 0)
96       hd_data->boot = boot_milo;
97     else
98       hd_data->boot = boot_aboot;
99
100     ct->family = cpu_variation;
101     ct->model = cpu_revision;
102     ct->stepping = 0;
103     ct->cache = 0;
104     ct->clock = (hz + 500000) / 1000000;
105
106     if(platform && strcmp(platform, "0")) {
107       ct->platform = new_str(platform);
108     }
109
110     if(!cpus) cpus = 1;         /* at least 1 machine had a "cpus: 0" entry... */
111     for(u = 0; u < cpus; u++) {
112       hd = add_hd_entry(hd_data, __LINE__, 0);
113       hd->base_class = bc_internal;
114       hd->sub_class = sc_int_cpu;
115       hd->slot = u;
116       hd->detail = new_mem(sizeof *hd->detail);
117       hd->detail->type = hd_detail_cpu;
118       if(u) {
119         hd->detail->cpu.data = ct1 = new_mem(sizeof *ct);
120         *ct1 = *ct;
121         ct1->model_name = new_str(ct1->model_name);
122         ct1->vend_name = new_str(ct1->vend_name);
123       }
124       else {
125         hd->detail->cpu.data = ct;
126       }
127     }
128
129   }
130 #endif  /* __alpha__ */
131
132
133 #ifdef __sparc__
134   *cpu_id = *fpu_id = *promlib = *prom = *type = *mmu = 0;
135   cpus = cpus_active = bogo = 0;
136
137   for(sl = hd_data->cpu; sl; sl = sl->next) {
138     if(sscanf(sl->str, "cpu             : %79[^\n]", cpu_id) == 1);
139     if(sscanf(sl->str, "fpu             : %79[^\n]", fpu_id) == 1);
140     if(sscanf(sl->str, "promlib         : %79[^\n]", promlib) == 1);
141     if(sscanf(sl->str, "prom            : %79[^\n]", prom) == 1);
142     if(sscanf(sl->str, "type            : %79[^\n]", type) == 1);
143     if(sscanf(sl->str, "ncpus probed    : %u", &cpus) == 1);
144     if(sscanf(sl->str, "ncpus active    : %u", &cpus_active) == 1);
145     if(sscanf(sl->str, "BogoMips        : %u", &bogo) == 1);
146     if(sscanf(sl->str, "MMU Type        : %79[^\n]", mmu) == 1);
147   }
148
149   if(*cpu_id) {
150     for(u = 0; u < cpus; u++) {
151       ct = new_mem(sizeof *ct);
152       ct->platform = new_str (type);
153       if(strcmp (type, "sun4u") == 0)
154         ct->architecture = arch_sparc64;
155       else
156         ct->architecture = arch_sparc;
157
158       ct->model_name = new_str(cpu_id);
159       hd_data->boot = boot_silo;
160
161       hd = add_hd_entry(hd_data, __LINE__, 0);
162       hd->base_class = bc_internal;
163       hd->sub_class = sc_int_cpu;
164       hd->slot = u;
165       hd->detail = new_mem(sizeof *hd->detail);
166       hd->detail->type = hd_detail_cpu;
167       hd->detail->cpu.data = ct;
168     }
169   }
170 #endif  /* sparc */
171
172
173 #ifdef __i386__
174   *model_id = *vendor_id = *features = 0;
175   bogo = mhz = cache = family = model = stepping = 0;
176
177   for(sl = hd_data->cpu; sl; sl = sl->next) {
178     if(sscanf(sl->str, "model name : %79[^\n]", model_id) == 1);
179     if(sscanf(sl->str, "vendor_id : %79[^\n]", vendor_id) == 1);
180     if(sscanf(sl->str, "flags : %255[^\n]", features) == 1);
181     if(sscanf(sl->str, "bogomips : %u", &bogo) == 1);
182     if(sscanf(sl->str, "cpu MHz : %u", &mhz) == 1);
183     if(sscanf(sl->str, "cache size : %u KB", &cache) == 1);
184
185     if(sscanf(sl->str, "cpu family : %u", &family) == 1);
186     if(sscanf(sl->str, "model : %u", &model) == 1);
187     if(sscanf(sl->str, "stepping : %u", &stepping) == 1);
188
189     if(strstr(sl->str, "processor") == sl->str || !sl->next) {          /* EOF */
190       if(*model_id || *vendor_id) {     /* at least one of those */
191         ct = new_mem(sizeof *ct);
192         ct->architecture = arch_intel;
193         if(model_id) ct->model_name = new_str(model_id);
194         if(vendor_id) ct->vend_name = new_str(vendor_id);
195         ct->family = family;
196         ct->model = model;
197         ct->stepping = stepping;
198         ct->cache = cache;
199         hd_data->boot = boot_lilo;
200
201         /* round clock to typical values */
202         if(mhz >= 38 && mhz <= 42)
203           mhz = 40;
204         else if(mhz >= 88 && mhz <= 92)
205           mhz = 90;
206         else {
207           unsigned u, v;
208
209           u = (mhz + 2) % 100;
210           v = (mhz + 2) / 100;
211           if(u <= 4)
212             u = 2;
213           else if(u >= 25 && u <= 29)
214             u = 25 + 2;
215           else if(u >= 33 && u <= 37)
216             u = 33 + 2;
217           else if(u >= 50 && u <= 54)
218             u = 50 + 2;
219           else if(u >= 66 && u <= 70)
220             u = 66 + 2;
221           else if(u >= 75 && u <= 79)
222             u = 75 + 2;
223           else if(u >= 80 && u <= 84)   /* there are 180MHz PPros */
224             u = 80 + 2;
225           u -= 2;
226           mhz = v * 100 + u;
227         }
228
229         ct->clock = mhz;
230
231         hd = add_hd_entry(hd_data, __LINE__, 0);
232         hd->base_class = bc_internal;
233         hd->sub_class = sc_int_cpu;
234         hd->slot = cpus;
235         hd->detail = new_mem(sizeof *hd->detail);
236         hd->detail->type = hd_detail_cpu;
237         hd->detail->cpu.data = ct;
238
239         if(*features) {
240           for(t0 = features; (t = strsep(&t0, " ")); ) {
241             add_str_list(&ct->features, t);
242           }
243         }
244
245         *model_id = *vendor_id = 0;
246         bogo = mhz = cache = family = model= 0;
247         cpus++;
248       }
249     }
250   }
251 #endif /* __i386__  */
252
253
254 #ifdef __PPC__
255   *model_id = *vendor_id = *motherboard = 0;
256   bogo = mhz = cache = family = model = stepping = 0;
257
258   for(sl = hd_data->cpu; sl; sl = sl->next) {
259     if(sscanf(sl->str, "machine : %79[^\n]", vendor_id) == 1);
260   }
261
262   for(sl = hd_data->cpu; sl; sl = sl->next) {
263     if(sscanf(sl->str, "cpu : %79[^\n]", model_id) == 1);
264     if(sscanf(sl->str, "motherboard : %79[^\n]", motherboard) == 1);
265     if(sscanf(sl->str, "bogomips : %u", &bogo) == 1);
266     if(sscanf(sl->str, "clock : %u", &mhz) == 1);
267     if(sscanf(sl->str, "L2 cache : %u KB", &cache) == 1);
268
269     if(strstr(sl->str, "processor") == sl->str || !sl->next) {          /* EOF */
270       if(*model_id) {   /* at least one of those */
271         ct = new_mem(sizeof *ct);
272         ct->architecture = arch_ppc;
273         if(model_id) ct->model_name = new_str(model_id);
274         if(vendor_id) ct->vend_name = new_str(vendor_id);
275         if(motherboard) ct->platform = new_str(motherboard);
276         ct->family = family;
277         ct->model = model;
278         ct->stepping = stepping;
279         ct->cache = cache;
280         hd_data->boot = boot_ppc;
281         ct->clock = mhz;
282
283         hd = add_hd_entry(hd_data, __LINE__, 0);
284         hd->base_class = bc_internal;
285         hd->sub_class = sc_int_cpu;
286         hd->slot = cpus;
287         hd->detail = new_mem(sizeof *hd->detail);
288         hd->detail->type = hd_detail_cpu;
289         hd->detail->cpu.data = ct;
290
291         if(ct->vend_name && !strcmp(ct->vend_name, "PowerBook") && !hd_data->color_code) {
292           hd_data->color_code = 7;      // black
293         }
294         
295         *model_id = 0;
296         bogo = mhz = cache = family = model= 0;
297         cpus++;
298       }
299     }
300   }
301 #endif /* __PPC__  */
302
303
304 #ifdef __ia64__
305   *model_id = *vendor_id = *features = 0;
306   mhz = stepping = 0;
307
308   for(sl = hd_data->cpu; sl; sl = sl->next) {
309     if(sscanf(sl->str, "model : %79[^\n]", model_id) == 1);
310     if(sscanf(sl->str, "vendor : %79[^\n]", vendor_id) == 1);
311     if(sscanf(sl->str, "features : %255[^\n]", features) == 1);
312     if(sscanf(sl->str, "cpu MHz : %u", &mhz) == 1);
313     if(sscanf(sl->str, "revision : %u", &stepping) == 1);
314
315     if(strstr(sl->str, "processor") == sl->str || !sl->next) {          /* EOF */
316       if(*model_id || *vendor_id) {     /* at least one of those */
317         ct = new_mem(sizeof *ct);
318         ct->architecture = arch_ia64;
319         if(model_id) ct->model_name = new_str(model_id);
320         if(vendor_id) ct->vend_name = new_str(vendor_id);
321         ct->stepping = stepping;
322         hd_data->boot = boot_ia64;
323
324         /* round clock to typical values */
325         if(mhz >= 38 && mhz <= 42)
326           mhz = 40;
327         else if(mhz >= 88 && mhz <= 92)
328           mhz = 90;
329         else {
330           unsigned u, v;
331
332           u = (mhz + 2) % 100;
333           v = (mhz + 2) / 100;
334           if(u <= 4)
335             u = 2;
336           else if(u >= 25 && u <= 29)
337             u = 25 + 2;
338           else if(u >= 33 && u <= 37)
339             u = 33 + 2;
340           else if(u >= 50 && u <= 54)
341             u = 50 + 2;
342           else if(u >= 66 && u <= 70)
343             u = 66 + 2;
344           else if(u >= 75 && u <= 79)
345             u = 75 + 2;
346           else if(u >= 80 && u <= 84)   /* there are 180MHz PPros */
347             u = 80 + 2;
348           u -= 2;
349           mhz = v * 100 + u;
350         }
351
352         ct->clock = mhz;
353
354         hd = add_hd_entry(hd_data, __LINE__, 0);
355         hd->base_class = bc_internal;
356         hd->sub_class = sc_int_cpu;
357         hd->slot = cpus;
358         hd->detail = new_mem(sizeof *hd->detail);
359         hd->detail->type = hd_detail_cpu;
360         hd->detail->cpu.data = ct;
361
362         if(*features) {
363           for(t0 = features; (t = strsep(&t0, " ")); ) {
364             add_str_list(&ct->features, t);
365           }
366         }
367
368         *model_id = *vendor_id = 0;
369         mhz = 0;
370         cpus++;
371       }
372     }
373   }
374 #endif /* __ia64__  */
375
376
377 #ifdef __s390__
378   *vendor_id = 0;
379   bogo = 0;
380
381   for(sl = hd_data->cpu; sl; sl = sl->next) {
382     if(sscanf(sl->str, "vendor_id : %79[^\n]", vendor_id) == 1);
383     if(sscanf(sl->str, "bogomips per cpu : %u", &bogo) == 1);
384   }
385
386   for(sl = hd_data->cpu; sl; sl = sl->next) {
387     if(
388       sscanf(sl->str, "processor %u : version = %u , identification = %u , machine = %u", &u0, &u1, &u2, &u3) == 4
389     ) {
390       ct = new_mem(sizeof *ct);
391       ct->architecture = arch_s390;
392       if(vendor_id) ct->vend_name = new_str(vendor_id);
393       ct->stepping = u1;
394       hd_data->boot = boot_s390;
395
396       hd = add_hd_entry(hd_data, __LINE__, 0);
397       hd->base_class = bc_internal;
398       hd->sub_class = sc_int_cpu;
399       hd->slot = cpus;
400       hd->detail = new_mem(sizeof *hd->detail);
401       hd->detail->type = hd_detail_cpu;
402       hd->detail->cpu.data = ct;
403
404       bogo = 0;
405       cpus++;
406     }
407   }
408 #endif /* __s390__  */
409 }
410
411
412 /*
413  * Add some cpu data to the global log.
414  */
415 void dump_cpu_data(hd_data_t *hd_data)
416 {
417   str_list_t *sl;
418
419   ADD2LOG("----- /proc/cpuinfo -----\n");
420   for(sl = hd_data->cpu; sl; sl = sl->next) {
421     ADD2LOG("  %s", sl->str);
422   }
423   ADD2LOG("----- /proc/cpuinfo end -----\n");
424 }
425