Back to index

lshw  02.16
cpuid.cc
Go to the documentation of this file.
00001 #include "version.h"
00002 #include "config.h"
00003 #include "cpuid.h"
00004 #include <stdio.h>
00005 #include <string.h>
00006 #include <unistd.h>
00007 #include <fcntl.h>
00008 #include <sys/stat.h>
00009 #include <sys/time.h>
00010 
00011 __ID("@(#) $Id: cpuid.cc 2433 2012-01-10 22:01:30Z lyonel $");
00012 
00013 #if defined(__i386__) || defined(__alpha__)
00014 
00015 static hwNode *getcache(hwNode & node,
00016 int n = 0)
00017 {
00018   char cachename[10];
00019   hwNode *cache = NULL;
00020 
00021   if (n < 0)
00022     n = 0;
00023 
00024   snprintf(cachename, sizeof(cachename), "cache:%d", n);
00025   cache = node.getChild(string(cachename));
00026 
00027   if (cache)
00028     return cache;
00029 
00030 // "cache:0" is equivalent to "cache" if we only have L1 cache
00031   if ((n == 0) && (node.countChildren(hw::memory) <= 1))
00032     cache = node.getChild(string("cache"));
00033   if (cache)
00034     return cache;
00035   else
00036     return NULL;
00037 }
00038 
00039 
00040 static hwNode *getcpu(hwNode & node,
00041 int n = 0)
00042 {
00043   char cpubusinfo[10];
00044   hwNode *cpu = NULL;
00045 
00046   if (n < 0)
00047     n = 0;
00048 
00049   snprintf(cpubusinfo, sizeof(cpubusinfo), "cpu@%d", n);
00050   cpu = node.findChildByBusInfo(cpubusinfo);
00051 
00052   if (cpu)
00053     return cpu;
00054 
00055   if (n > 0)
00056     return NULL;
00057 
00058   hwNode *core = node.getChild("core");
00059 
00060   if (core)
00061   {
00062     hwNode cpu("cpu", hw::processor);
00063 
00064     cpu.setBusInfo(cpubusinfo);
00065     cpu.addHint("icon", string("cpu"));
00066     cpu.claim();
00067 
00068     return core->addChild(cpu);
00069   }
00070   else
00071     return NULL;
00072 }
00073 #endif                                            // __i386__ || __alpha__
00074 
00075 #ifdef __i386__
00076 
00077 /* %ebx may be the PIC register.  */
00078 #define cpuid_up(in,a,b,c,d)\
00079   __asm__ ("xchgl\t%%ebx, %1\n\t"                \
00080           "cpuid\n\t"                                   \
00081           "xchgl\t%%ebx, %1\n\t"                 \
00082           : "=a" (a), "=r" (b), "=c" (c), "=d" (d)      \
00083           : "0" (in))
00084 
00085 static void cpuid(int cpunumber,
00086 unsigned long idx,
00087 unsigned long &eax,
00088 unsigned long &ebx,
00089 unsigned long &ecx,
00090 unsigned long &edx)
00091 {
00092   char cpuname[50];
00093   int fd = -1;
00094   unsigned char buffer[16];
00095 
00096   snprintf(cpuname, sizeof(cpuname), "/dev/cpu/%d/cpuid", cpunumber);
00097   fd = open(cpuname, O_RDONLY);
00098   if (fd >= 0)
00099   {
00100     lseek(fd, idx, SEEK_CUR);
00101     memset(buffer, 0, sizeof(buffer));
00102     if(read(fd, buffer, sizeof(buffer)) == sizeof(buffer))
00103     {
00104       eax = (*(unsigned long *) buffer);
00105       ebx = (*(unsigned long *) (buffer + 4));
00106       ecx = (*(unsigned long *) (buffer + 8));
00107       edx = (*(unsigned long *) (buffer + 12));
00108     }
00109     close(fd);
00110   }
00111   else
00112     cpuid_up(idx, eax, ebx, ecx, edx);
00113 }
00114 
00115 
00116 /* Decode Intel TLB and cache info descriptors */
00117 static void decode_intel_tlb(int x,
00118 long long &l1cache,
00119 long long &l2cache)
00120 {
00121   x &= 0xff;
00122   switch (x)
00123   {
00124     case 0:
00125       break;
00126     case 0x1:
00127 // Instruction TLB: 4KB pages, 4-way set assoc, 32 entries
00128       break;
00129     case 0x2:
00130 // Instruction TLB: 4MB pages, 4-way set assoc, 2 entries
00131       break;
00132     case 0x3:
00133 // Data TLB: 4KB pages, 4-way set assoc, 64 entries
00134       break;
00135     case 0x4:
00136 // Data TLB: 4MB pages, 4-way set assoc, 8 entries
00137       break;
00138     case 0x6:
00139 // 1st-level instruction cache: 8KB, 4-way set assoc, 32 byte line size
00140       l1cache += 8 * 1024;
00141       break;
00142     case 0x8:
00143 // 1st-level instruction cache: 16KB, 4-way set assoc, 32 byte line size
00144       l1cache += 16 * 1024;
00145       break;
00146     case 0xa:
00147 // 1st-level data cache: 8KB, 2-way set assoc, 32 byte line size
00148       l1cache += 8 * 1024;
00149       break;
00150     case 0xc:
00151 // 1st-level data cache: 16KB, 4-way set assoc, 32 byte line size
00152       l1cache += 16 * 1024;
00153       break;
00154     case 0x40:
00155 // No 2nd-level cache, or if 2nd-level cache exists, no 3rd-level cache
00156       break;
00157     case 0x41:
00158 // 2nd-level cache: 128KB, 4-way set assoc, 32 byte line size
00159       l2cache = 128 * 1024;
00160       break;
00161     case 0x42:
00162 // 2nd-level cache: 256KB, 4-way set assoc, 32 byte line size
00163       l2cache = 256 * 1024;
00164       break;
00165     case 0x43:
00166 // 2nd-level cache: 512KB, 4-way set assoc, 32 byte line size
00167       l2cache = 512 * 1024;
00168       break;
00169     case 0x44:
00170 // 2nd-level cache: 1MB, 4-way set assoc, 32 byte line size
00171       l2cache = 1024 * 1024;
00172       break;
00173     case 0x45:
00174 // 2nd-level cache: 2MB, 4-way set assoc, 32 byte line size
00175       l2cache = 2 * 1024 * 1024;
00176       break;
00177     case 0x50:
00178 // Instruction TLB: 4KB and 2MB or 4MB pages, 64 entries
00179       break;
00180     case 0x51:
00181 // Instruction TLB: 4KB and 2MB or 4MB pages, 128 entries
00182       break;
00183     case 0x52:
00184 // Instruction TLB: 4KB and 2MB or 4MB pages, 256 entries
00185       break;
00186     case 0x5b:
00187 // Data TLB: 4KB and 4MB pages, 64 entries
00188       break;
00189     case 0x5c:
00190 // Data TLB: 4KB and 4MB pages, 128 entries
00191       break;
00192     case 0x5d:
00193 // Data TLB: 4KB and 4MB pages, 256 entries
00194       break;
00195     case 0x66:
00196 // 1st-level data cache: 8KB, 4-way set assoc, 64 byte line size
00197       l1cache += 8 * 1024;
00198       break;
00199     case 0x67:
00200 // 1st-level data cache: 16KB, 4-way set assoc, 64 byte line size
00201       l1cache += 16 * 1024;
00202       break;
00203     case 0x68:
00204 // 1st-level data cache: 32KB, 4-way set assoc, 64 byte line size
00205       l1cache += 32 * 1024;
00206       break;
00207     case 0x70:
00208 // Trace cache: 12K-micro-op, 4-way set assoc
00209       break;
00210     case 0x71:
00211 // Trace cache: 16K-micro-op, 4-way set assoc
00212       break;
00213     case 0x72:
00214 // Trace cache: 32K-micro-op, 4-way set assoc
00215       break;
00216     case 0x79:
00217 // 2nd-level cache: 128KB, 8-way set assoc, sectored, 64 byte line size
00218       l2cache += 128 * 1024;
00219       break;
00220     case 0x7a:
00221 // 2nd-level cache: 256KB, 8-way set assoc, sectored, 64 byte line size
00222       l2cache += 256 * 1024;
00223       break;
00224     case 0x7b:
00225 // 2nd-level cache: 512KB, 8-way set assoc, sectored, 64 byte line size
00226       l2cache += 512 * 1024;
00227       break;
00228     case 0x7c:
00229 // 2nd-level cache: 1MB, 8-way set assoc, sectored, 64 byte line size
00230       l2cache += 1024 * 1024;
00231       break;
00232     case 0x82:
00233 // 2nd-level cache: 256KB, 8-way set assoc, 32 byte line size
00234       l2cache += 256 * 1024;
00235       break;
00236     case 0x83:
00237 // 2nd-level cache: 512KB, 8-way set assoc 32 byte line size
00238       l2cache += 512 * 1024;
00239       break;
00240     case 0x84:
00241 // 2nd-level cache: 1MB, 8-way set assoc, 32 byte line size
00242       l2cache += 1024 * 1024;
00243       break;
00244     case 0x85:
00245 // 2nd-level cache: 2MB, 8-way set assoc, 32 byte line size
00246       l2cache += 2 * 1024 * 1024;
00247       break;
00248     default:
00249 // unknown TLB/cache descriptor
00250       break;
00251   }
00252 }
00253 
00254 
00255 static bool dointel(unsigned long maxi,
00256 hwNode * cpu,
00257 int cpunumber = 0)
00258 {
00259   char buffer[1024];
00260   unsigned long signature = 0, flags = 0, bflags = 0, eax = 0, ebx = 0, ecx = 0, edx = 0, unused = 0;
00261   int stepping, model, family;
00262 
00263   if (!cpu)
00264     return false;
00265 
00266   cpu->addHint("logo", string("intel"));
00267 
00268   if (maxi >= 1)
00269   {
00270     cpuid(cpunumber, 1, eax, ebx, ecx, edx);
00271 
00272     signature = eax;
00273 
00274     stepping = eax & 0xf;
00275     model = (eax >> 4) & 0xf;
00276     family = (eax >> 8) & 0xf;
00277     flags = edx;
00278     bflags = ebx;
00279 
00280     snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping);
00281     cpu->setVersion(buffer);
00282 
00283     if(ecx & (1 << 5))
00284       cpu->addCapability("vmx", _("CPU virtualization (Vanderpool)"));
00285 
00286 /* Hyper-Threading Technology */
00287     if (flags & (1 << 28))
00288     {
00289       char buff[20];
00290       unsigned int nr_ht = (bflags >> 16) & 0xFF;
00291       unsigned int phys_id = (bflags >> 24) & 0xFF;
00292 
00293       snprintf(buff, sizeof(buff), "%d", phys_id);
00294       cpu->setConfig("id", buff);
00295 
00296       hwNode logicalcpu("logicalcpu", hw::processor);
00297       logicalcpu.setDescription(_("Logical CPU"));
00298       logicalcpu.addCapability("logical", _("Logical CPU"));
00299       logicalcpu.setWidth(cpu->getWidth());
00300       logicalcpu.claim();
00301       cpu->addCapability("ht", _("HyperThreading"));
00302 
00303       if(nr_ht>1)
00304         for(unsigned int i=0; i< nr_ht; i++)
00305       {
00306         snprintf(buff, sizeof(buff), "CPU:%d.%d", phys_id, i);
00307         logicalcpu.setHandle(buff);
00308         logicalcpu.setPhysId(phys_id, i+1);
00309         cpu->addChild(logicalcpu);
00310         cpu->claim();
00311       }
00312     }
00313 
00314   }
00315 
00316   if (maxi >= 2)
00317   {
00318 /*
00319  * Decode TLB and cache info
00320  */
00321     int ntlb, i;
00322     long long l1cache = 0, l2cache = 0;
00323 
00324     ntlb = 255;
00325     for (i = 0; i < ntlb; i++)
00326     {
00327       cpuid(cpunumber, 2, eax, ebx, ecx, edx);
00328       ntlb = eax & 0xff;
00329       decode_intel_tlb(eax >> 8, l1cache, l2cache);
00330       decode_intel_tlb(eax >> 16, l1cache, l2cache);
00331       decode_intel_tlb(eax >> 24, l1cache, l2cache);
00332 
00333       if ((ebx & 0x80000000) == 0)
00334       {
00335         decode_intel_tlb(ebx, l1cache, l2cache);
00336         decode_intel_tlb(ebx >> 8, l1cache, l2cache);
00337         decode_intel_tlb(ebx >> 16, l1cache, l2cache);
00338         decode_intel_tlb(ebx >> 24, l1cache, l2cache);
00339       }
00340       if ((ecx & 0x80000000) == 0)
00341       {
00342         decode_intel_tlb(ecx, l1cache, l2cache);
00343         decode_intel_tlb(ecx >> 8, l1cache, l2cache);
00344         decode_intel_tlb(ecx >> 16, l1cache, l2cache);
00345         decode_intel_tlb(ecx >> 24, l1cache, l2cache);
00346       }
00347       if ((edx & 0x80000000) == 0)
00348       {
00349         decode_intel_tlb(edx, l1cache, l2cache);
00350         decode_intel_tlb(edx >> 8, l1cache, l2cache);
00351         decode_intel_tlb(edx >> 16, l1cache, l2cache);
00352         decode_intel_tlb(edx >> 24, l1cache, l2cache);
00353       }
00354     }
00355 
00356     if (l1cache != 0)
00357     {
00358       hwNode *l1 = getcache(*cpu, 0);
00359       hwNode *l2 = getcache(*cpu, 1);
00360 
00361       if (l1)
00362       {
00363         l1->setSize(l1cache);
00364         if (l1->getDescription() == "")
00365           l1->setDescription(_("L1 cache"));
00366       }
00367       else
00368       {
00369         hwNode cache("cache",
00370           hw::memory);
00371         cache.setSize(l1cache);
00372         cache.setDescription(_("L1 cache"));
00373 
00374         cpu->addChild(cache);
00375       }
00376 
00377       if (l2cache != 0)
00378       {
00379         if (l2 && (l2cache != 0))
00380         {
00381           l2->setSize(l2cache);
00382           if (l2->getDescription() == "")
00383             l2->setDescription(_("L2 cache"));
00384         }
00385         else
00386         {
00387           hwNode cache("cache",
00388             hw::memory);
00389           cache.setSize(l2cache);
00390           cache.setDescription(_("L2 cache"));
00391 
00392           cpu->addChild(cache);
00393         }
00394       }
00395     }
00396   }
00397 
00398   if (maxi >= 3)
00399   {
00400     cpuid(cpunumber, 3, unused, unused, ecx, edx);
00401 
00402     snprintf(buffer, sizeof(buffer),
00403       "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX",
00404       signature >> 16,
00405       signature & 0xffff,
00406       edx >> 16, edx & 0xffff, ecx >> 16, ecx & 0xffff);
00407 
00408     cpu->setSerial(buffer);
00409   }
00410   else
00411     cpu->setSerial("");
00412 
00413   return true;
00414 }
00415 
00416 
00417 static bool doamd(unsigned long maxi,
00418 hwNode * cpu,
00419 int cpunumber = 0)
00420 {
00421   unsigned long maxei = 0, eax, ebx, ecx, edx;
00422   long long l1cache = 0, l2cache = 0;
00423   unsigned int family = 0, model = 0, stepping = 0;
00424   char buffer[1024];
00425 
00426   if (maxi < 1)
00427     return false;
00428 
00429   cpu->addHint("logo", string("amd"));
00430 
00431   cpuid(cpunumber, 1, eax, ebx, ecx, edx);
00432   stepping = eax & 0xf;
00433   model = (eax >> 4) & 0xf;
00434   family = (eax >> 8) & 0xf;
00435   snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping);
00436   cpu->setVersion(buffer);
00437 
00438   cpuid(cpunumber, 0x80000000, maxei, ebx, ecx, edx);
00439 
00440   if (maxei >= 0x80000005)
00441   {
00442     cpuid(cpunumber, 0x80000005, eax, ebx, ecx, edx);
00443 
00444     l1cache = (ecx >> 24) * 1024;                 // data cache
00445     l1cache += (edx >> 24) * 1024;                // instruction cache
00446   }
00447   if (maxei >= 0x80000006)
00448   {
00449     cpuid(cpunumber, 0x80000006, eax, ebx, ecx, edx);
00450 
00451     l2cache = (ecx >> 16) * 1024;
00452   }
00453 
00454   if (l1cache != 0)
00455   {
00456     hwNode *l1 = cpu->getChild("cache:0");
00457     hwNode *l2 = cpu->getChild("cache:1");
00458 
00459     if (l1)
00460       l1->setSize(l1cache);
00461     else
00462     {
00463       hwNode newl1("cache",
00464         hw::memory);
00465 
00466       newl1.setDescription(_("L1 cache"));
00467       newl1.setSize(l1cache);
00468 
00469       cpu->addChild(newl1);
00470     }
00471     if (l2 && l2cache)
00472       l2->setSize(l2cache);
00473     else
00474     {
00475       hwNode newl2("cache",
00476         hw::memory);
00477 
00478       newl2.setDescription(_("L2 cache"));
00479       newl2.setSize(l2cache);
00480 
00481       if (l2cache)
00482         cpu->addChild(newl2);
00483     }
00484   }
00485 
00486   return true;
00487 }
00488 
00489 
00490 static bool docyrix(unsigned long maxi,
00491 hwNode * cpu,
00492 int cpunumber = 0)
00493 {
00494   unsigned long eax, ebx, ecx, edx;
00495   unsigned int family = 0, model = 0, stepping = 0;
00496   char buffer[1024];
00497 
00498   if (maxi < 1)
00499     return false;
00500 
00501   cpuid(cpunumber, 1, eax, ebx, ecx, edx);
00502   stepping = eax & 0xf;
00503   model = (eax >> 4) & 0xf;
00504   family = (eax >> 8) & 0xf;
00505   snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping);
00506   cpu->setVersion(buffer);
00507 
00508   return true;
00509 }
00510 
00511 
00512 static __inline__ bool flag_is_changeable_p(unsigned int flag)
00513 {
00514   unsigned int f1, f2;
00515   __asm__ volatile ("pushfl\n\t"
00516     "pushfl\n\t"
00517     "popl %0\n\t"
00518     "movl %0,%1\n\t"
00519     "xorl %2,%0\n\t"
00520     "pushl %0\n\t"
00521     "popfl\n\t"
00522     "pushfl\n\t" "popl %0\n\t" "popfl\n\t":"=&r" (f1),
00523     "=&r"(f2):"ir"(flag));
00524   return ((f1 ^ f2) & flag) != 0;
00525 }
00526 
00527 
00528 static bool haveCPUID()
00529 {
00530   return flag_is_changeable_p(0x200000);
00531 }
00532 
00533 
00534 /*
00535  * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
00536  * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
00537  *
00538  */
00539 
00540 static __inline__ unsigned long long int rdtsc()
00541 {
00542   unsigned long long int x;
00543   __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
00544   return x;
00545 }
00546 
00547 
00548 static float estimate_MHz(int cpunum,
00549 long sleeptime = 250000)
00550 {
00551   struct timezone tz;
00552   struct timeval tvstart, tvstop;
00553   unsigned long long int cycles[2];               /* gotta be 64 bit */
00554   float microseconds;                             /* total time taken */
00555   unsigned long eax, ebx, ecx, edx;
00556   double freq = 1.0f;
00557 
00558 /*
00559  * Make sure we have a TSC (and hence RDTSC)
00560  */
00561   cpuid(cpunum, 1, eax, ebx, ecx, edx);
00562   if ((edx & (1 << 4)) == 0)
00563   {
00564     return 0;                                     // can't estimate frequency
00565   }
00566 
00567   memset(&tz, 0, sizeof(tz));
00568 
00569 /*
00570  * get this function in cached memory
00571  */
00572   gettimeofday(&tvstart, &tz);
00573   cycles[0] = rdtsc();
00574   gettimeofday(&tvstart, &tz);
00575 
00576 /*
00577  * we don't trust that this is any specific length of time
00578  */
00579   usleep(sleeptime);
00580 
00581   gettimeofday(&tvstop, &tz);
00582   cycles[1] = rdtsc();
00583   gettimeofday(&tvstop, &tz);
00584 
00585   microseconds = (tvstop.tv_sec - tvstart.tv_sec) * 1000000 +
00586     (tvstop.tv_usec - tvstart.tv_usec);
00587 
00588   return (float) (cycles[1] - cycles[0]) / (microseconds / freq);
00589 }
00590 
00591 
00592 static float average_MHz(int cpunum,
00593 int tries = 2)
00594 {
00595   float frequency = 0;
00596 
00597   for (int i = 1; i <= tries; i++)
00598     frequency += estimate_MHz(cpunum, i * 150000);
00599 
00600   if (tries > 0)
00601     return frequency / (float) tries;
00602   else
00603     return 0;
00604 }
00605 
00606 
00607 static long round_MHz(float fMHz)
00608 {
00609   long MHz = (long)fMHz;
00610 
00611   if ((MHz % 50) > 15)
00612     return ((MHz / 50) * 50) + 50;
00613   else
00614     return ((MHz / 50) * 50);
00615 }
00616 
00617 
00618 bool scan_cpuid(hwNode & n)
00619 {
00620   unsigned long maxi, ebx, ecx, edx;
00621   hwNode *cpu = NULL;
00622   int currentcpu = 0;
00623 
00624   if (!haveCPUID())
00625     return false;
00626 
00627   while ((cpu = getcpu(n, currentcpu)))
00628   {
00629     cpu->claim(true);                             // claim the cpu and all its children
00630     cpuid(currentcpu, 0, maxi, ebx, ecx, edx);
00631     maxi &= 0xffff;
00632 
00633     switch (ebx)
00634     {
00635       case 0x756e6547:                            /* Intel */
00636         dointel(maxi, cpu, currentcpu);
00637         break;
00638       case 0x68747541:                            /* AMD */
00639         doamd(maxi, cpu, currentcpu);
00640         break;
00641       case 0x69727943:                            /* Cyrix */
00642         docyrix(maxi, cpu, currentcpu);
00643         break;
00644       default:
00645         return false;
00646     }
00647 
00648     cpu->claim(true);                             // claim the cpu and all its children
00649     if (cpu->getSize() == 0)
00650       cpu->setSize((unsigned long long) (1000000uL * round_MHz(average_MHz(currentcpu))));
00651 
00652     currentcpu++;
00653   }
00654 
00655   return true;
00656 }
00657 
00658 
00659 #else
00660 
00661 #ifdef __alpha__
00662 
00663 #define BWX (1 << 0)
00664 #define FIX (1 << 1)
00665 #define CIX (1 << 2)
00666 #define MVI (1 << 8)
00667 #define PAT (1 << 9)
00668 #define PMI (1 << 12)
00669 
00670 bool scan_cpuid(hwNode & n)
00671 {
00672   hwNode *cpu = NULL;
00673   int currentcpu = 0;
00674   unsigned long ver = 0, mask = 0;
00675 
00676   while (cpu = getcpu(n, currentcpu))
00677   {
00678     asm("implver %0":"=r"(ver));
00679     asm("amask %1, %0": "=r"(mask):"r"(-1));
00680 
00681     cpu->setVendor("Digital Equipment Corporation");
00682     cpu->setProduct("Alpha");
00683     cpu->setWidth(64);
00684 
00685     if ((~mask) & BWX)
00686       cpu->addCapability("BWX");
00687     if ((~mask) & FIX)
00688       cpu->addCapability("FIX");
00689     if ((~mask) & CIX)
00690       cpu->addCapability("CIX");
00691     if ((~mask) & MVI)
00692       cpu->addCapability("MVI");
00693     if ((~mask) & PAT)
00694       cpu->addCapability("PAT");
00695     if ((~mask) & PMI)
00696       cpu->addCapability("PMI");
00697 
00698     switch (ver)
00699     {
00700       case 0:
00701         cpu->setVersion("EV4");
00702         break;
00703       case 1:
00704         switch (~mask)
00705         {
00706           case 0:
00707             cpu->setVersion("EV5");
00708             break;
00709           case BWX:
00710             cpu->setVersion("EV56");
00711             break;
00712           case BWX | MVI:
00713             cpu->setVersion("PCA56");
00714             break;
00715           default:
00716             cpu->setVersion("EV5 unknown");
00717         }
00718         break;
00719       case 2:
00720         switch (~mask)
00721         {
00722           case BWX | FIX | MVI | PAT:
00723             cpu->setVersion("EV6");
00724             break;
00725           case BWX | FIX | MVI | PAT | CIX:
00726             cpu->setVersion("EV67");
00727             break;
00728           case BWX | FIX | MVI | PAT | CIX | PMI:
00729             cpu->setVersion("EV68");
00730             break;
00731           default:
00732             cpu->setVersion("EV6 unknown");
00733         }
00734         break;
00735       case 3:
00736         switch (~mask)
00737         {
00738           case BWX | FIX | MVI | PAT | CIX | PMI:
00739             cpu->setVersion("EV7x");
00740             break;
00741           default:
00742             cpu->setVersion("EV7 unknown");
00743         }
00744         break;
00745     }
00746 
00747     currentcpu++;
00748   }
00749 
00750   return true;
00751 }
00752 
00753 
00754 #else
00755 
00756 bool scan_cpuid(hwNode & n)
00757 {
00758   return true;
00759 }
00760 #endif                                            /* __alpha__ */
00761 #endif                                            /* __i386__ */