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