diff options
author | Peter Jones <pjones@redhat.com> | 2006-02-16 18:34:32 +0000 |
---|---|---|
committer | Peter Jones <pjones@redhat.com> | 2006-02-16 18:34:32 +0000 |
commit | 03d121720443bd4c5655c3479b3a1d6f9420d369 (patch) | |
tree | 0b6c9fd737fa3d17cd7330b59c09e32b075302b2 | |
parent | 68abce4ec26668883dcf8b8be53098af64d3083b (diff) | |
download | anaconda-03d121720443bd4c5655c3479b3a1d6f9420d369.tar.gz anaconda-03d121720443bd4c5655c3479b3a1d6f9420d369.tar.xz anaconda-03d121720443bd4c5655c3479b3a1d6f9420d369.zip |
- add routines to determine how many cores per package
(theoretically, this is all correct. It seems to work on !x86_64, and the
"i386" version appears to work on em64t machines running the i386 code.
x86_64 where multiple cores/threads exist so far haven't been tested,
and em64t in x86_64 mode doesn't seem to work. Relevant documentation from
the cpu vendors is at http://people.redhat.com/pjones/cpuid/
-rw-r--r-- | isys/smp.c | 163 |
1 files changed, 139 insertions, 24 deletions
diff --git a/isys/smp.c b/isys/smp.c index d0850cce1..cc0504140 100644 --- a/isys/smp.c +++ b/isys/smp.c @@ -16,6 +16,8 @@ #include <sys/types.h> #include <limits.h> +#include "smp.h" + #ifdef DIET typedef unsigned short u_short; typedef unsigned long u_long; @@ -552,42 +554,148 @@ static int intelDetectSMP(void) /* ---- end mptable mess ---- */ #endif /* __i386__ || __x86_64__ */ -#if defined(__i386__) -static inline unsigned int cpuid_ebx(int op) +#if defined(__i386__) || defined(__x86_64__) +#if defined(__x86_64__) +/* seems not to work */ +u_int32_t cpuid_eax(u_int32_t op) { - unsigned int eax, ebx; - - __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx" - : "=a" (eax), "=g" (ebx) + u_int32_t eax=op, out; + __asm__("cpuid; movl %%eax,%[out]" + : [in] "=a" (eax), [out] "=g" (out) : "0" (op) - : "cx", "dx"); - return ebx; + : "bx", "cx", "dx"); + return eax; } -#elif defined(__x86_64__) -static inline unsigned int cpuid_ebx(int op) +/* seems to work? */ +u_int32_t cpuid_ebx(u_int32_t op) { - unsigned int eax, ebx; - + u_int32_t eax, ebx; __asm__("cpuid" : "=a" (eax), "=b" (ebx) : "0" (op) : "cx", "dx"); return ebx; } +/* seems not to work */ +u_int32_t cpuid_edx(u_int32_t op) +{ + u_int32_t eax, edx, out; + __asm__("cpuid; movl %%edx,%[out]" + : "=a" (eax), "=d" (edx), [out] "=g" (out) + : "0" (op) + : "bx", "cx"); + printf("eax: %x\n", eax); + printf("edx: %x\n", edx); + printf("out: %x\n", out); + return edx; +} +#elif defined(__i386__) +/* this one works */ +static inline u_int32_t cpuid_eax(u_int32_t fn) +{ + u_int32_t eax, ebx; + __asm__("pushl %%ebx; cpuid; movl %%eax,%[out]; popl %%ebx" + : [out] "=a" (eax), "=g" (ebx) + : "0" (fn) + : "cx", "dx"); + return eax; +} +/* this one works */ +static inline u_int32_t cpuid_ebx(u_int32_t fn) +{ + u_int32_t eax, ebx; + __asm__("pushl %%ebx; cpuid; movl %%ebx,%[out]; popl %%ebx" + : "=a" (eax), [out] "=g" (ebx) + : "0" (fn) + : "cx", "dx"); + return ebx; +} +/* no idea */ +static inline u_int32_t cpuid_edx(u_int32_t fn) +{ + u_int32_t eax, ebx, edx; + __asm__("pushl %%ebx; cpuid; movl %%edx,%[out]; popl %%ebx" + : "=a" (eax), "=g" (ebx), [out] "=g" (edx) + : "0" (fn) + : "cx"); + return edx; +} #endif -#if defined(__i386__) || defined(__x86_64__) +typedef enum { + VENDOR_UNKNOWN, + VENDOR_OTHER, + VENDOR_INTEL, + VENDOR_AMD, +} vendor_t; + +vendor_t detectVendor(void) +{ + FILE *f; + static vendor_t vendor = VENDOR_UNKNOWN; + + if (vendor != VENDOR_UNKNOWN) + return vendor; + vendor = VENDOR_OTHER; + + f = fopen("/proc/cpuinfo", "r"); + if (f) { + char buf[1024] = {'\0'}; + + while (fgets(buf, 1024, f) != NULL) { + if (!strncmp(buf, "vendor_id\t: ", 12)) { + if (!strncmp(buf+12, "GenuineIntel\n", 13)) + vendor = VENDOR_INTEL; + else if (!strncmp(buf+12, "AuthenticAMD\n", 13)) + vendor = VENDOR_AMD; + } + } + fclose(f); + } + + return vendor; +} + int detectHT(void) { - uint32_t ebx = 0; + u_int32_t ebx = 0; int logical_procs = 0; ebx = cpuid_ebx(1); logical_procs = (ebx & 0xff0000) >> 16; - + return logical_procs; } +int detectCoresPerPackage(void) +{ + int cores_per_package = 1; + vendor_t vendor = detectVendor(); + + switch (vendor) { + case VENDOR_INTEL: { + /* <geoff> cpuid eax=04h returns cores per physical package + in eax[31-26]+1 (i.e. 0 for 1, 1 for 2) */ + u_int32_t eax = 0; + + eax = cpuid_eax(4); + cores_per_package = ((eax & 0xfc000000) >> 26) + 1; + break; + } + case VENDOR_AMD: { + u_int32_t edx = 0; + + edx = cpuid_edx(0x80000008); + cores_per_package = (edx & 0xff) + 1; + break; + } + case VENDOR_OTHER: + default: + break; + } + return cores_per_package; +} + int detectSummit(void) { return groupForSMP(MODE_SUMMIT_CHECK); @@ -602,20 +710,20 @@ int detectHT(void) f = fopen("/proc/cpuinfo", "r"); if (f) { - char buf[1024]; - - while (fgets (buf, 1024, f) != NULL) { - if (!strncmp (buf, "siblings : ", 13)) { + char buf[1024]; + + while (fgets(buf, 1024, f) != NULL) { + if (!strncmp(buf, "siblings : ", 13)) { errno = 0; nthreads = strtol(buf+13, NULL, 0); if (nthreads == LONG_MAX || nthreads == LONG_MIN || errno) nthreads = 1; - break; - } - } - fclose(f); + break; + } + } + fclose(f); } else - return 1; + return 1; return nthreads ? nthreads : 1; } @@ -786,6 +894,13 @@ int detectSummit(void) #endif /* __i386__ */ +#if !defined(__i386__) && !defined(__x86_64__) +int detectCoresPerPackage(void) +{ + return 1; +} +#endif + int detectSMP(void) { static int isSMP = -1; |