162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (C) 2003 - 2004 Dominik Brodowski <linux@dominikbrodowski.de> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on code found in 662306a36Sopenharmony_ci * linux/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c 762306a36Sopenharmony_ci * and originally developed by Jeremy Fitzhardinge. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * USAGE: simply run it to decode the current settings on CPU 0, 1062306a36Sopenharmony_ci * or pass the CPU number as argument, or pass the MSR content 1162306a36Sopenharmony_ci * as argument. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <stdio.h> 1562306a36Sopenharmony_ci#include <stdlib.h> 1662306a36Sopenharmony_ci#include <stdint.h> 1762306a36Sopenharmony_ci#include <unistd.h> 1862306a36Sopenharmony_ci#include <errno.h> 1962306a36Sopenharmony_ci#include <fcntl.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <sys/types.h> 2262306a36Sopenharmony_ci#include <sys/stat.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define MCPU 32 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define MSR_IA32_PERF_STATUS 0x198 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int rdmsr(unsigned int cpu, unsigned int msr, 2962306a36Sopenharmony_ci unsigned int *lo, unsigned int *hi) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci int fd; 3262306a36Sopenharmony_ci char file[20]; 3362306a36Sopenharmony_ci unsigned long long val; 3462306a36Sopenharmony_ci int retval = -1; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci *lo = *hi = 0; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (cpu > MCPU) 3962306a36Sopenharmony_ci goto err1; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci sprintf(file, "/dev/cpu/%d/msr", cpu); 4262306a36Sopenharmony_ci fd = open(file, O_RDONLY); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (fd < 0) 4562306a36Sopenharmony_ci goto err1; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (lseek(fd, msr, SEEK_CUR) == -1) 4862306a36Sopenharmony_ci goto err2; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (read(fd, &val, 8) != 8) 5162306a36Sopenharmony_ci goto err2; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci *lo = (uint32_t )(val & 0xffffffffull); 5462306a36Sopenharmony_ci *hi = (uint32_t )(val>>32 & 0xffffffffull); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci retval = 0; 5762306a36Sopenharmony_cierr2: 5862306a36Sopenharmony_ci close(fd); 5962306a36Sopenharmony_cierr1: 6062306a36Sopenharmony_ci return retval; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void decode (unsigned int msr) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci unsigned int multiplier; 6662306a36Sopenharmony_ci unsigned int mv; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci multiplier = ((msr >> 8) & 0xFF); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mv = (((msr & 0xFF) * 16) + 700); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci printf("0x%x means multiplier %d @ %d mV\n", msr, multiplier, mv); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int decode_live(unsigned int cpu) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci unsigned int lo, hi; 7862306a36Sopenharmony_ci int err; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci err = rdmsr(cpu, MSR_IA32_PERF_STATUS, &lo, &hi); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (err) { 8362306a36Sopenharmony_ci printf("can't get MSR_IA32_PERF_STATUS for cpu %d\n", cpu); 8462306a36Sopenharmony_ci printf("Possible trouble: you don't run an Enhanced SpeedStep capable cpu\n"); 8562306a36Sopenharmony_ci printf("or you are not root, or the msr driver is not present\n"); 8662306a36Sopenharmony_ci return 1; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci decode(lo); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciint main (int argc, char **argv) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci unsigned int cpu, mode = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (argc < 2) 9962306a36Sopenharmony_ci cpu = 0; 10062306a36Sopenharmony_ci else { 10162306a36Sopenharmony_ci cpu = strtoul(argv[1], NULL, 0); 10262306a36Sopenharmony_ci if (cpu >= MCPU) 10362306a36Sopenharmony_ci mode = 1; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (mode) 10762306a36Sopenharmony_ci decode(cpu); 10862306a36Sopenharmony_ci else 10962306a36Sopenharmony_ci decode_live(cpu); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 113