Initial commit; kernel source import

This commit is contained in:
Nathan
2025-04-06 23:50:55 -05:00
commit 25c6d769f4
45093 changed files with 18199410 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
#if defined(__i386__) || defined(__x86_64__)
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <pci/pci.h>
#include "helpers/helpers.h"
#define MSR_AMD_PSTATE_STATUS 0xc0010063
#define MSR_AMD_PSTATE 0xc0010064
#define MSR_AMD_PSTATE_LIMIT 0xc0010061
union msr_pstate {
struct {
unsigned fid:6;
unsigned did:3;
unsigned vid:7;
unsigned res1:6;
unsigned nbdid:1;
unsigned res2:2;
unsigned nbvid:7;
unsigned iddval:8;
unsigned idddiv:2;
unsigned res3:21;
unsigned en:1;
} bits;
unsigned long long val;
};
static int get_did(int family, union msr_pstate pstate)
{
int t;
if (family == 0x12)
t = pstate.val & 0xf;
else
t = pstate.bits.did;
return t;
}
static int get_cof(int family, union msr_pstate pstate)
{
int t;
int fid, did;
did = get_did(family, pstate);
t = 0x10;
fid = pstate.bits.fid;
if (family == 0x11)
t = 0x8;
return (100 * (fid + t)) >> did;
}
/* Needs:
* cpu -> the cpu that gets evaluated
* cpu_family -> The cpu's family (0x10, 0x12,...)
* boots_states -> how much boost states the machines support
*
* Fills up:
* pstates -> a pointer to an array of size MAX_HW_PSTATES
* must be initialized with zeros.
* All available HW pstates (including boost states)
* no -> amount of pstates above array got filled up with
*
* returns zero on success, -1 on failure
*/
int decode_pstates(unsigned int cpu, unsigned int cpu_family,
int boost_states, unsigned long *pstates, int *no)
{
int i, psmax, pscur;
union msr_pstate pstate;
unsigned long long val;
/* Only read out frequencies from HW when CPU might be boostable
to keep the code as short and clean as possible.
Otherwise frequencies are exported via ACPI tables.
*/
if (cpu_family < 0x10 || cpu_family == 0x14)
return -1;
if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
return -1;
psmax = (val >> 4) & 0x7;
if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val))
return -1;
pscur = val & 0x7;
pscur += boost_states;
psmax += boost_states;
for (i = 0; i <= psmax; i++) {
if (i >= MAX_HW_PSTATES) {
fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
psmax, MAX_HW_PSTATES);
return -1;
}
if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
return -1;
pstates[i] = get_cof(cpu_family, pstate);
}
*no = i;
return 0;
}
int amd_pci_get_num_boost_states(int *active, int *states)
{
struct pci_access *pci_acc;
struct pci_dev *device;
uint8_t val = 0;
*active = *states = 0;
device = pci_slot_func_init(&pci_acc, 0x18, 4);
if (device == NULL)
return -ENODEV;
val = pci_read_byte(device, 0x15c);
if (val & 3)
*active = 1;
else
*active = 0;
*states = (val >> 2) & 7;
pci_cleanup(pci_acc);
return 0;
}
#endif /* defined(__i386__) || defined(__x86_64__) */

View File

@@ -0,0 +1,292 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <helpers/bitmask.h>
/* How many bits in an unsigned long */
#define bitsperlong (8 * sizeof(unsigned long))
/* howmany(a,b) : how many elements of size b needed to hold all of a */
#define howmany(x, y) (((x)+((y)-1))/(y))
/* How many longs in mask of n bits */
#define longsperbits(n) howmany(n, bitsperlong)
#define max(a, b) ((a) > (b) ? (a) : (b))
/*
* Allocate and free `struct bitmask *`
*/
/* Allocate a new `struct bitmask` with a size of n bits */
struct bitmask *bitmask_alloc(unsigned int n)
{
struct bitmask *bmp;
bmp = malloc(sizeof(*bmp));
if (bmp == 0)
return 0;
bmp->size = n;
bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
if (bmp->maskp == 0) {
free(bmp);
return 0;
}
return bmp;
}
/* Free `struct bitmask` */
void bitmask_free(struct bitmask *bmp)
{
if (bmp == 0)
return;
free(bmp->maskp);
bmp->maskp = (unsigned long *)0xdeadcdef; /* double free tripwire */
free(bmp);
}
/*
* The routines _getbit() and _setbit() are the only
* routines that actually understand the layout of bmp->maskp[].
*
* On little endian architectures, this could simply be an array of
* bytes. But the kernel layout of bitmasks _is_ visible to userspace
* via the sched_(set/get)affinity calls in Linux 2.6, and on big
* endian architectures, it is painfully obvious that this is an
* array of unsigned longs.
*/
/* Return the value (0 or 1) of bit n in bitmask bmp */
static unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
{
if (n < bmp->size)
return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1;
else
return 0;
}
/* Set bit n in bitmask bmp to value v (0 or 1) */
static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
{
if (n < bmp->size) {
if (v)
bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong);
else
bmp->maskp[n/bitsperlong] &=
~(1UL << (n % bitsperlong));
}
}
/*
* When parsing bitmask lists, only allow numbers, separated by one
* of the allowed next characters.
*
* The parameter 'sret' is the return from a sscanf "%u%c". It is
* -1 if the sscanf input string was empty. It is 0 if the first
* character in the sscanf input string was not a decimal number.
* It is 1 if the unsigned number matching the "%u" was the end of the
* input string. It is 2 if one or more additional characters followed
* the matched unsigned number. If it is 2, then 'nextc' is the first
* character following the number. The parameter 'ok_next_chars'
* is the nul-terminated list of allowed next characters.
*
* The mask term just scanned was ok if and only if either the numbers
* matching the %u were all of the input or if the next character in
* the input past the numbers was one of the allowed next characters.
*/
static int scan_was_ok(int sret, char nextc, const char *ok_next_chars)
{
return sret == 1 ||
(sret == 2 && strchr(ok_next_chars, nextc) != NULL);
}
static const char *nexttoken(const char *q, int sep)
{
if (q)
q = strchr(q, sep);
if (q)
q++;
return q;
}
/* Set a single bit i in bitmask */
struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
{
_setbit(bmp, i, 1);
return bmp;
}
/* Set all bits in bitmask: bmp = ~0 */
struct bitmask *bitmask_setall(struct bitmask *bmp)
{
unsigned int i;
for (i = 0; i < bmp->size; i++)
_setbit(bmp, i, 1);
return bmp;
}
/* Clear all bits in bitmask: bmp = 0 */
struct bitmask *bitmask_clearall(struct bitmask *bmp)
{
unsigned int i;
for (i = 0; i < bmp->size; i++)
_setbit(bmp, i, 0);
return bmp;
}
/* True if all bits are clear */
int bitmask_isallclear(const struct bitmask *bmp)
{
unsigned int i;
for (i = 0; i < bmp->size; i++)
if (_getbit(bmp, i))
return 0;
return 1;
}
/* True if specified bit i is set */
int bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
{
return _getbit(bmp, i);
}
/* Number of lowest set bit (min) */
unsigned int bitmask_first(const struct bitmask *bmp)
{
return bitmask_next(bmp, 0);
}
/* Number of highest set bit (max) */
unsigned int bitmask_last(const struct bitmask *bmp)
{
unsigned int i;
unsigned int m = bmp->size;
for (i = 0; i < bmp->size; i++)
if (_getbit(bmp, i))
m = i;
return m;
}
/* Number of next set bit at or above given bit i */
unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i)
{
unsigned int n;
for (n = i; n < bmp->size; n++)
if (_getbit(bmp, n))
break;
return n;
}
/*
* Parses a comma-separated list of numbers and ranges of numbers,
* with optional ':%u' strides modifying ranges, into provided bitmask.
* Some examples of input lists and their equivalent simple list:
* Input Equivalent to
* 0-3 0,1,2,3
* 0-7:2 0,2,4,6
* 1,3,5-7 1,3,5,6,7
* 0-3:2,8-15:4 0,2,8,12
*/
int bitmask_parselist(const char *buf, struct bitmask *bmp)
{
const char *p, *q;
bitmask_clearall(bmp);
q = buf;
while (p = q, q = nexttoken(q, ','), p) {
unsigned int a; /* begin of range */
unsigned int b; /* end of range */
unsigned int s; /* stride */
const char *c1, *c2; /* next tokens after '-' or ',' */
char nextc; /* char after sscanf %u match */
int sret; /* sscanf return (number of matches) */
sret = sscanf(p, "%u%c", &a, &nextc);
if (!scan_was_ok(sret, nextc, ",-"))
goto err;
b = a;
s = 1;
c1 = nexttoken(p, '-');
c2 = nexttoken(p, ',');
if (c1 != NULL && (c2 == NULL || c1 < c2)) {
sret = sscanf(c1, "%u%c", &b, &nextc);
if (!scan_was_ok(sret, nextc, ",:"))
goto err;
c1 = nexttoken(c1, ':');
if (c1 != NULL && (c2 == NULL || c1 < c2)) {
sret = sscanf(c1, "%u%c", &s, &nextc);
if (!scan_was_ok(sret, nextc, ","))
goto err;
}
}
if (!(a <= b))
goto err;
if (b >= bmp->size)
goto err;
while (a <= b) {
_setbit(bmp, a, 1);
a += s;
}
}
return 0;
err:
bitmask_clearall(bmp);
return -1;
}
/*
* emit(buf, buflen, rbot, rtop, len)
*
* Helper routine for bitmask_displaylist(). Write decimal number
* or range to buf+len, suppressing output past buf+buflen, with optional
* comma-prefix. Return len of what would be written to buf, if it
* all fit.
*/
static inline int emit(char *buf, int buflen, int rbot, int rtop, int len)
{
if (len > 0)
len += snprintf(buf + len, max(buflen - len, 0), ",");
if (rbot == rtop)
len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot);
else
len += snprintf(buf + len, max(buflen - len, 0), "%d-%d",
rbot, rtop);
return len;
}
/*
* Write decimal list representation of bmp to buf.
*
* Output format is a comma-separated list of decimal numbers and
* ranges. Consecutively set bits are shown as two hyphen-separated
* decimal numbers, the smallest and largest bit numbers set in
* the range. Output format is compatible with the format
* accepted as input by bitmap_parselist().
*
* The return value is the number of characters which would be
* generated for the given input, excluding the trailing '\0', as
* per ISO C99.
*/
int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp)
{
int len = 0;
/* current bit is 'cur', most recently seen range is [rbot, rtop] */
unsigned int cur, rbot, rtop;
if (buflen > 0)
*buf = 0;
rbot = cur = bitmask_first(bmp);
while (cur < bmp->size) {
rtop = cur;
cur = bitmask_next(bmp, cur+1);
if (cur >= bmp->size || cur > rtop + 1) {
len = emit(buf, buflen, rbot, rtop, len);
rbot = cur;
}
}
return len;
}

View File

@@ -0,0 +1,33 @@
#ifndef __CPUPOWER_BITMASK__
#define __CPUPOWER_BITMASK__
/* Taken over from libbitmask, a project initiated from sgi:
* Url: http://oss.sgi.com/projects/cpusets/
* Unfortunately it's not very widespread, therefore relevant parts are
* pasted here.
*/
struct bitmask {
unsigned int size;
unsigned long *maskp;
};
struct bitmask *bitmask_alloc(unsigned int n);
void bitmask_free(struct bitmask *bmp);
struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i);
struct bitmask *bitmask_setall(struct bitmask *bmp);
struct bitmask *bitmask_clearall(struct bitmask *bmp);
unsigned int bitmask_first(const struct bitmask *bmp);
unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i);
unsigned int bitmask_last(const struct bitmask *bmp);
int bitmask_isallclear(const struct bitmask *bmp);
int bitmask_isbitset(const struct bitmask *bmp, unsigned int i);
int bitmask_parselist(const char *buf, struct bitmask *bmp);
int bitmask_displaylist(char *buf, int len, const struct bitmask *bmp);
#endif /*__CPUPOWER_BITMASK__ */

View File

@@ -0,0 +1,178 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "helpers/helpers.h"
static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
"Unknown", "GenuineIntel", "AuthenticAMD",
};
#if defined(__i386__) || defined(__x86_64__)
/* from gcc */
#include <cpuid.h>
/*
* CPUID functions returning a single datum
*
* Define unsigned int cpuid_e[abcd]x(unsigned int op)
*/
#define cpuid_func(reg) \
unsigned int cpuid_##reg(unsigned int op) \
{ \
unsigned int eax, ebx, ecx, edx; \
__cpuid(op, eax, ebx, ecx, edx); \
return reg; \
}
cpuid_func(eax);
cpuid_func(ebx);
cpuid_func(ecx);
cpuid_func(edx);
#endif /* defined(__i386__) || defined(__x86_64__) */
/* get_cpu_info
*
* Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
*
* Returns 0 on success or a negativ error code
*
* TBD: Should there be a cpuid alternative for this if /proc is not mounted?
*/
int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info)
{
FILE *fp;
char value[64];
unsigned int proc, x;
unsigned int unknown = 0xffffff;
unsigned int cpuid_level, ext_cpuid_level;
int ret = -EINVAL;
cpu_info->vendor = X86_VENDOR_UNKNOWN;
cpu_info->family = unknown;
cpu_info->model = unknown;
cpu_info->stepping = unknown;
cpu_info->caps = 0;
fp = fopen("/proc/cpuinfo", "r");
if (!fp)
return -EIO;
while (!feof(fp)) {
if (!fgets(value, 64, fp))
continue;
value[63 - 1] = '\0';
if (!strncmp(value, "processor\t: ", 12))
sscanf(value, "processor\t: %u", &proc);
if (proc != cpu)
continue;
/* Get CPU vendor */
if (!strncmp(value, "vendor_id", 9)) {
for (x = 1; x < X86_VENDOR_MAX; x++) {
if (strstr(value, cpu_vendor_table[x]))
cpu_info->vendor = x;
}
/* Get CPU family, etc. */
} else if (!strncmp(value, "cpu family\t: ", 13)) {
sscanf(value, "cpu family\t: %u",
&cpu_info->family);
} else if (!strncmp(value, "model\t\t: ", 9)) {
sscanf(value, "model\t\t: %u",
&cpu_info->model);
} else if (!strncmp(value, "stepping\t: ", 10)) {
sscanf(value, "stepping\t: %u",
&cpu_info->stepping);
/* Exit -> all values must have been set */
if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
cpu_info->family == unknown ||
cpu_info->model == unknown ||
cpu_info->stepping == unknown) {
ret = -EINVAL;
goto out;
}
ret = 0;
goto out;
}
}
ret = -ENODEV;
out:
fclose(fp);
/* Get some useful CPU capabilities from cpuid */
if (cpu_info->vendor != X86_VENDOR_AMD &&
cpu_info->vendor != X86_VENDOR_INTEL)
return ret;
cpuid_level = cpuid_eax(0);
ext_cpuid_level = cpuid_eax(0x80000000);
/* Invariant TSC */
if (ext_cpuid_level >= 0x80000007 &&
(cpuid_edx(0x80000007) & (1 << 8)))
cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
/* Aperf/Mperf registers support */
if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
cpu_info->caps |= CPUPOWER_CAP_APERF;
/* AMD Boost state enable/disable register */
if (cpu_info->vendor == X86_VENDOR_AMD) {
if (ext_cpuid_level >= 0x80000007 &&
(cpuid_edx(0x80000007) & (1 << 9)))
cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
}
if (cpu_info->vendor == X86_VENDOR_INTEL) {
if (cpuid_level >= 6 &&
(cpuid_eax(6) & (1 << 1)))
cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
}
if (cpu_info->vendor == X86_VENDOR_INTEL) {
/* Intel's perf-bias MSR support */
if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
/* Intel's Turbo Ratio Limit support */
if (cpu_info->family == 6) {
switch (cpu_info->model) {
case 0x1A: /* Core i7, Xeon 5500 series
* Bloomfield, Gainstown NHM-EP
*/
case 0x1E: /* Core i7 and i5 Processor
* Clarksfield, Lynnfield, Jasper Forest
*/
case 0x1F: /* Core i7 and i5 Processor - Nehalem */
case 0x25: /* Westmere Client
* Clarkdale, Arrandale
*/
case 0x2C: /* Westmere EP - Gulftown */
cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
case 0x2A: /* SNB */
case 0x2D: /* SNB Xeon */
case 0x3A: /* IVB */
case 0x3E: /* IVB Xeon */
cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
break;
case 0x2E: /* Nehalem-EX Xeon - Beckton */
case 0x2F: /* Westmere-EX Xeon - Eagleton */
default:
break;
}
}
}
/* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
cpuid_level, ext_cpuid_level, cpu_info->caps);
*/
return ret;
}

View File

@@ -0,0 +1,195 @@
/*
* (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
*
* Licensed under the terms of the GNU GPL License version 2.
*
* Miscellaneous helpers which do not fit or are worth
* to put into separate headers
*/
#ifndef __CPUPOWERUTILS_HELPERS__
#define __CPUPOWERUTILS_HELPERS__
#include <libintl.h>
#include <locale.h>
#include "helpers/bitmask.h"
/* Internationalization ****************************/
#ifdef NLS
#define _(String) gettext(String)
#ifndef gettext_noop
#define gettext_noop(String) String
#endif
#define N_(String) gettext_noop(String)
#else /* !NLS */
#define _(String) String
#define N_(String) String
#endif
/* Internationalization ****************************/
extern int run_as_root;
extern struct bitmask *cpus_chosen;
/* Global verbose (-d) stuff *********************************/
/*
* define DEBUG via global Makefile variable
* Debug output is sent to stderr, do:
* cpupower monitor 2>/tmp/debug
* to split debug output away from normal output
*/
#ifdef DEBUG
extern int be_verbose;
#define dprint(fmt, ...) { \
if (be_verbose) { \
fprintf(stderr, "%s: " fmt, \
__func__, ##__VA_ARGS__); \
} \
}
#else
static inline void dprint(const char *fmt, ...) { }
#endif
extern int be_verbose;
/* Global verbose (-v) stuff *********************************/
/* cpuid and cpuinfo helpers **************************/
enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
X86_VENDOR_AMD, X86_VENDOR_MAX};
#define CPUPOWER_CAP_INV_TSC 0x00000001
#define CPUPOWER_CAP_APERF 0x00000002
#define CPUPOWER_CAP_AMD_CBP 0x00000004
#define CPUPOWER_CAP_PERF_BIAS 0x00000008
#define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010
#define CPUPOWER_CAP_IS_SNB 0x00000020
#define CPUPOWER_CAP_INTEL_IDA 0x00000040
#define MAX_HW_PSTATES 10
struct cpupower_cpu_info {
enum cpupower_cpu_vendor vendor;
unsigned int family;
unsigned int model;
unsigned int stepping;
/* CPU capabilities read out from cpuid */
unsigned long long caps;
};
/* get_cpu_info
*
* Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
*
* Returns 0 on success or a negativ error code
* Only used on x86, below global's struct values are zero/unknown on
* other archs
*/
extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
extern struct cpupower_cpu_info cpupower_cpu_info;
/* cpuid and cpuinfo helpers **************************/
struct cpuid_core_info {
int pkg;
int core;
int cpu;
/* flags */
unsigned int is_online:1;
};
/* CPU topology/hierarchy parsing ******************/
struct cpupower_topology {
/* Amount of CPU cores, packages and threads per core in the system */
unsigned int cores;
unsigned int pkgs;
unsigned int threads; /* per core */
/* Array gets mallocated with cores entries, holding per core info */
struct cpuid_core_info *core_info;
};
extern int get_cpu_topology(struct cpupower_topology *cpu_top);
extern void cpu_topology_release(struct cpupower_topology cpu_top);
/* CPU topology/hierarchy parsing ******************/
/* X86 ONLY ****************************************/
#if defined(__i386__) || defined(__x86_64__)
#include <pci/pci.h>
/* Read/Write msr ****************************/
extern int read_msr(int cpu, unsigned int idx, unsigned long long *val);
extern int write_msr(int cpu, unsigned int idx, unsigned long long val);
extern int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val);
extern int msr_intel_get_perf_bias(unsigned int cpu);
extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu);
/* Read/Write msr ****************************/
/* PCI stuff ****************************/
extern int amd_pci_get_num_boost_states(int *active, int *states);
extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain,
int bus, int slot, int func, int vendor,
int dev);
extern struct pci_dev *pci_slot_func_init(struct pci_access **pacc,
int slot, int func);
/* PCI stuff ****************************/
/* AMD HW pstate decoding **************************/
extern int decode_pstates(unsigned int cpu, unsigned int cpu_family,
int boost_states, unsigned long *pstates, int *no);
/* AMD HW pstate decoding **************************/
extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
int *active, int * states);
/*
* CPUID functions returning a single datum
*/
unsigned int cpuid_eax(unsigned int op);
unsigned int cpuid_ebx(unsigned int op);
unsigned int cpuid_ecx(unsigned int op);
unsigned int cpuid_edx(unsigned int op);
/* cpuid and cpuinfo helpers **************************/
/* X86 ONLY ********************************************/
#else
static inline int decode_pstates(unsigned int cpu, unsigned int cpu_family,
int boost_states, unsigned long *pstates,
int *no)
{ return -1; };
static inline int read_msr(int cpu, unsigned int idx, unsigned long long *val)
{ return -1; };
static inline int write_msr(int cpu, unsigned int idx, unsigned long long val)
{ return -1; };
static inline int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
{ return -1; };
static inline int msr_intel_get_perf_bias(unsigned int cpu)
{ return -1; };
static inline unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu)
{ return 0; };
/* Read/Write msr ****************************/
static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
int *active, int * states)
{ return -1; }
/* cpuid and cpuinfo helpers **************************/
static inline unsigned int cpuid_eax(unsigned int op) { return 0; };
static inline unsigned int cpuid_ebx(unsigned int op) { return 0; };
static inline unsigned int cpuid_ecx(unsigned int op) { return 0; };
static inline unsigned int cpuid_edx(unsigned int op) { return 0; };
#endif /* defined(__i386__) || defined(__x86_64__) */
#endif /* __CPUPOWERUTILS_HELPERS__ */

View File

@@ -0,0 +1,27 @@
#if defined(__i386__) || defined(__x86_64__)
#include "helpers/helpers.h"
int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active,
int *states)
{
struct cpupower_cpu_info cpu_info;
int ret;
*support = *active = *states = 0;
ret = get_cpu_info(0, &cpu_info);
if (ret)
return ret;
if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) {
*support = 1;
amd_pci_get_num_boost_states(active, states);
if (ret <= 0)
return ret;
*support = 1;
} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA)
*support = *active = 1;
return 0;
}
#endif /* #if defined(__i386__) || defined(__x86_64__) */

View File

@@ -0,0 +1,115 @@
#if defined(__i386__) || defined(__x86_64__)
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include "helpers/helpers.h"
/* Intel specific MSRs */
#define MSR_IA32_PERF_STATUS 0x198
#define MSR_IA32_MISC_ENABLES 0x1a0
#define MSR_IA32_ENERGY_PERF_BIAS 0x1b0
#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1ad
/*
* read_msr
*
* Will return 0 on success and -1 on failure.
* Possible errno values could be:
* EFAULT -If the read/write did not fully complete
* EIO -If the CPU does not support MSRs
* ENXIO -If the CPU does not exist
*/
int read_msr(int cpu, unsigned int idx, unsigned long long *val)
{
int fd;
char msr_file_name[64];
sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
fd = open(msr_file_name, O_RDONLY);
if (fd < 0)
return -1;
if (lseek(fd, idx, SEEK_CUR) == -1)
goto err;
if (read(fd, val, sizeof *val) != sizeof *val)
goto err;
close(fd);
return 0;
err:
close(fd);
return -1;
}
/*
* write_msr
*
* Will return 0 on success and -1 on failure.
* Possible errno values could be:
* EFAULT -If the read/write did not fully complete
* EIO -If the CPU does not support MSRs
* ENXIO -If the CPU does not exist
*/
int write_msr(int cpu, unsigned int idx, unsigned long long val)
{
int fd;
char msr_file_name[64];
sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
fd = open(msr_file_name, O_WRONLY);
if (fd < 0)
return -1;
if (lseek(fd, idx, SEEK_CUR) == -1)
goto err;
if (write(fd, &val, sizeof val) != sizeof val)
goto err;
close(fd);
return 0;
err:
close(fd);
return -1;
}
int msr_intel_get_perf_bias(unsigned int cpu)
{
unsigned long long val;
int ret;
if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
return -1;
ret = read_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &val);
if (ret)
return ret;
return val;
}
int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
{
int ret;
if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
return -1;
ret = write_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, val);
if (ret)
return ret;
return 0;
}
unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu)
{
unsigned long long val;
int ret;
if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO))
return -1;
ret = read_msr(cpu, MSR_NEHALEM_TURBO_RATIO_LIMIT, &val);
if (ret)
return ret;
return val;
}
#endif

View File

@@ -0,0 +1,55 @@
#if defined(__i386__) || defined(__x86_64__)
#include <helpers/helpers.h>
/*
* pci_acc_init
*
* PCI access helper function depending on libpci
*
* **pacc : if a valid pci_dev is returned
* *pacc must be passed to pci_acc_cleanup to free it
*
* domain: domain
* bus: bus
* slot: slot
* func: func
* vendor: vendor
* device: device
* Pass -1 for one of the six above to match any
*
* Returns :
* struct pci_dev which can be used with pci_{read,write}_* functions
* to access the PCI config space of matching pci devices
*/
struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, int bus,
int slot, int func, int vendor, int dev)
{
struct pci_filter filter_nb_link = { domain, bus, slot, func,
vendor, dev };
struct pci_dev *device;
*pacc = pci_alloc();
if (*pacc == NULL)
return NULL;
pci_init(*pacc);
pci_scan_bus(*pacc);
for (device = (*pacc)->devices; device; device = device->next) {
if (pci_filter_match(&filter_nb_link, device))
return device;
}
pci_cleanup(*pacc);
return NULL;
}
/* Typically one wants to get a specific slot(device)/func of the root domain
and bus */
struct pci_dev *pci_slot_func_init(struct pci_access **pacc, int slot,
int func)
{
return pci_acc_init(pacc, 0, 0, slot, func, -1, -1);
}
#endif /* defined(__i386__) || defined(__x86_64__) */

View File

@@ -0,0 +1,358 @@
/*
* (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
* (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc.
*
* Licensed under the terms of the GNU GPL License version 2.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "helpers/sysfs.h"
unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
{
int fd;
ssize_t numread;
fd = open(path, O_RDONLY);
if (fd == -1)
return 0;
numread = read(fd, buf, buflen - 1);
if (numread < 1) {
close(fd);
return 0;
}
buf[numread] = '\0';
close(fd);
return (unsigned int) numread;
}
/*
* Detect whether a CPU is online
*
* Returns:
* 1 -> if CPU is online
* 0 -> if CPU is offline
* negative errno values in error case
*/
int sysfs_is_cpu_online(unsigned int cpu)
{
char path[SYSFS_PATH_MAX];
int fd;
ssize_t numread;
unsigned long long value;
char linebuf[MAX_LINE_LEN];
char *endp;
struct stat statbuf;
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
if (stat(path, &statbuf) != 0)
return 0;
/*
* kernel without CONFIG_HOTPLUG_CPU
* -> cpuX directory exists, but not cpuX/online file
*/
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
if (stat(path, &statbuf) != 0)
return 1;
fd = open(path, O_RDONLY);
if (fd == -1)
return -errno;
numread = read(fd, linebuf, MAX_LINE_LEN - 1);
if (numread < 1) {
close(fd);
return -EIO;
}
linebuf[numread] = '\0';
close(fd);
value = strtoull(linebuf, &endp, 0);
if (value > 1 || value < 0)
return -EINVAL;
return value;
}
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/*
* helper function to read file from /sys into given buffer
* fname is a relative path under "cpuX/cpuidle/stateX/" dir
* cstates starting with 0, C0 is not counted as cstate.
* This means if you want C1 info, pass 0 as idlestate param
*/
unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
const char *fname, char *buf, size_t buflen)
{
char path[SYSFS_PATH_MAX];
int fd;
ssize_t numread;
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
cpu, idlestate, fname);
fd = open(path, O_RDONLY);
if (fd == -1)
return 0;
numread = read(fd, buf, buflen - 1);
if (numread < 1) {
close(fd);
return 0;
}
buf[numread] = '\0';
close(fd);
return (unsigned int) numread;
}
/* read access to files which contain one numeric value */
enum idlestate_value {
IDLESTATE_USAGE,
IDLESTATE_POWER,
IDLESTATE_LATENCY,
IDLESTATE_TIME,
MAX_IDLESTATE_VALUE_FILES
};
static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
[IDLESTATE_USAGE] = "usage",
[IDLESTATE_POWER] = "power",
[IDLESTATE_LATENCY] = "latency",
[IDLESTATE_TIME] = "time",
};
static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
unsigned int idlestate,
enum idlestate_value which)
{
unsigned long long value;
unsigned int len;
char linebuf[MAX_LINE_LEN];
char *endp;
if (which >= MAX_IDLESTATE_VALUE_FILES)
return 0;
len = sysfs_idlestate_read_file(cpu, idlestate,
idlestate_value_files[which],
linebuf, sizeof(linebuf));
if (len == 0)
return 0;
value = strtoull(linebuf, &endp, 0);
if (endp == linebuf || errno == ERANGE)
return 0;
return value;
}
/* read access to files which contain one string */
enum idlestate_string {
IDLESTATE_DESC,
IDLESTATE_NAME,
MAX_IDLESTATE_STRING_FILES
};
static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
[IDLESTATE_DESC] = "desc",
[IDLESTATE_NAME] = "name",
};
static char *sysfs_idlestate_get_one_string(unsigned int cpu,
unsigned int idlestate,
enum idlestate_string which)
{
char linebuf[MAX_LINE_LEN];
char *result;
unsigned int len;
if (which >= MAX_IDLESTATE_STRING_FILES)
return NULL;
len = sysfs_idlestate_read_file(cpu, idlestate,
idlestate_string_files[which],
linebuf, sizeof(linebuf));
if (len == 0)
return NULL;
result = strdup(linebuf);
if (result == NULL)
return NULL;
if (result[strlen(result) - 1] == '\n')
result[strlen(result) - 1] = '\0';
return result;
}
unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate)
{
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
}
unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
unsigned int idlestate)
{
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
}
unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
unsigned int idlestate)
{
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
}
char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
{
return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
}
char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
{
return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
}
/*
* Returns number of supported C-states of CPU core cpu
* Negativ in error case
* Zero if cpuidle does not export any C-states
*/
int sysfs_get_idlestate_count(unsigned int cpu)
{
char file[SYSFS_PATH_MAX];
struct stat statbuf;
int idlestates = 1;
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
return -ENODEV;
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
return 0;
while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
"cpu%u/cpuidle/state%d", cpu, idlestates);
idlestates++;
}
idlestates--;
return idlestates;
}
/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
/*
* helper function to read file from /sys into given buffer
* fname is a relative path under "cpu/cpuidle/" dir
*/
static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
size_t buflen)
{
char path[SYSFS_PATH_MAX];
snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
return sysfs_read_file(path, buf, buflen);
}
/* read access to files which contain one string */
enum cpuidle_string {
CPUIDLE_GOVERNOR,
CPUIDLE_GOVERNOR_RO,
CPUIDLE_DRIVER,
MAX_CPUIDLE_STRING_FILES
};
static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
[CPUIDLE_GOVERNOR] = "current_governor",
[CPUIDLE_GOVERNOR_RO] = "current_governor_ro",
[CPUIDLE_DRIVER] = "current_driver",
};
static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
{
char linebuf[MAX_LINE_LEN];
char *result;
unsigned int len;
if (which >= MAX_CPUIDLE_STRING_FILES)
return NULL;
len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
linebuf, sizeof(linebuf));
if (len == 0)
return NULL;
result = strdup(linebuf);
if (result == NULL)
return NULL;
if (result[strlen(result) - 1] == '\n')
result[strlen(result) - 1] = '\0';
return result;
}
char *sysfs_get_cpuidle_governor(void)
{
char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
if (!tmp)
return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
else
return tmp;
}
char *sysfs_get_cpuidle_driver(void)
{
return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
}
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/*
* Get sched_mc or sched_smt settings
* Pass "mc" or "smt" as argument
*
* Returns negative value on failure
*/
int sysfs_get_sched(const char *smt_mc)
{
return -ENODEV;
}
/*
* Get sched_mc or sched_smt settings
* Pass "mc" or "smt" as argument
*
* Returns negative value on failure
*/
int sysfs_set_sched(const char *smt_mc, int val)
{
return -ENODEV;
}

View File

@@ -0,0 +1,30 @@
#ifndef __CPUPOWER_HELPERS_SYSFS_H__
#define __CPUPOWER_HELPERS_SYSFS_H__
#define PATH_TO_CPU "/sys/devices/system/cpu/"
#define MAX_LINE_LEN 255
#define SYSFS_PATH_MAX 255
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
extern int sysfs_is_cpu_online(unsigned int cpu);
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate);
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
unsigned int idlestate);
extern unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
unsigned int idlestate);
extern char *sysfs_get_idlestate_name(unsigned int cpu,
unsigned int idlestate);
extern char *sysfs_get_idlestate_desc(unsigned int cpu,
unsigned int idlestate);
extern int sysfs_get_idlestate_count(unsigned int cpu);
extern char *sysfs_get_cpuidle_governor(void);
extern char *sysfs_get_cpuidle_driver(void);
extern int sysfs_get_sched(const char *smt_mc);
extern int sysfs_set_sched(const char *smt_mc, int val);
#endif /* __CPUPOWER_HELPERS_SYSFS_H__ */

View File

@@ -0,0 +1,116 @@
/*
* (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
*
* Licensed under the terms of the GNU GPL License version 2.
*
* ToDo: Needs to be done more properly for AMD/Intel specifics
*/
/* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */
/* Be careful: Need to pass unsigned to the sort, so that offlined cores are
in the end, but double check for -1 for offlined cpus at other places */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <helpers/helpers.h>
#include <helpers/sysfs.h>
/* returns -1 on failure, 0 on success */
static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
{
char linebuf[MAX_LINE_LEN];
char *endp;
char path[SYSFS_PATH_MAX];
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
cpu, fname);
if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
return -1;
*result = strtol(linebuf, &endp, 0);
if (endp == linebuf || errno == ERANGE)
return -1;
return 0;
}
static int __compare(const void *t1, const void *t2)
{
struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
if (top1->pkg < top2->pkg)
return -1;
else if (top1->pkg > top2->pkg)
return 1;
else if (top1->core < top2->core)
return -1;
else if (top1->core > top2->core)
return 1;
else if (top1->cpu < top2->cpu)
return -1;
else if (top1->cpu > top2->cpu)
return 1;
else
return 0;
}
/*
* Returns amount of cpus, negative on error, cpu_top must be
* passed to cpu_topology_release to free resources
*
* Array is sorted after ->pkg, ->core, then ->cpu
*/
int get_cpu_topology(struct cpupower_topology *cpu_top)
{
int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
if (cpu_top->core_info == NULL)
return -ENOMEM;
cpu_top->pkgs = cpu_top->cores = 0;
for (cpu = 0; cpu < cpus; cpu++) {
cpu_top->core_info[cpu].cpu = cpu;
cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
if(sysfs_topology_read_file(
cpu,
"physical_package_id",
&(cpu_top->core_info[cpu].pkg)) < 0)
return -1;
if(sysfs_topology_read_file(
cpu,
"core_id",
&(cpu_top->core_info[cpu].core)) < 0)
return -1;
}
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
__compare);
/* Count the number of distinct pkgs values. This works
because the primary sort of the core_info struct was just
done by pkg value. */
last_pkg = cpu_top->core_info[0].pkg;
for(cpu = 1; cpu < cpus; cpu++) {
if(cpu_top->core_info[cpu].pkg != last_pkg) {
last_pkg = cpu_top->core_info[cpu].pkg;
cpu_top->pkgs++;
}
}
cpu_top->pkgs++;
/* Intel's cores count is not consecutively numbered, there may
* be a core_id of 3, but none of 2. Assume there always is 0
* Get amount of cores by counting duplicates in a package
for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
if (cpu_top->core_info[cpu].core == 0)
cpu_top->cores++;
*/
return cpus;
}
void cpu_topology_release(struct cpupower_topology cpu_top)
{
free(cpu_top.core_info);
}