#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/bus.h>
#include "acpicpu.h"
#if NACPICPU > 0
#include <dev/acpi/acpidev.h>
#endif
#define ID16(MHz, mV, bus_clk) \
{ ((((MHz * 100 + 50) / bus_clk) << 8) | ((mV ? mV - 700 : 0) >> 4)), \
MHz }
struct est_op {
uint16_t ctrl;
uint16_t mhz;
uint16_t pct;
};
static struct est_op pm130_900_ulv[] = {
ID16( 900, 1004, BUS100),
ID16( 800, 988, BUS100),
ID16( 600, 844, BUS100),
};
static struct est_op pm130_1000_ulv[] = {
ID16(1000, 1004, BUS100),
ID16( 900, 988, BUS100),
ID16( 800, 972, BUS100),
ID16( 600, 844, BUS100),
};
static struct est_op pm130_1100_ulv[] = {
ID16(1100, 1004, BUS100),
ID16(1000, 988, BUS100),
ID16( 900, 972, BUS100),
ID16( 800, 956, BUS100),
ID16( 600, 844, BUS100),
};
static struct est_op pm130_1100_lv[] = {
ID16(1100, 1180, BUS100),
ID16(1000, 1164, BUS100),
ID16( 900, 1100, BUS100),
ID16( 800, 1020, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm130_1200_lv[] = {
ID16(1200, 1180, BUS100),
ID16(1100, 1164, BUS100),
ID16(1000, 1100, BUS100),
ID16( 900, 1020, BUS100),
ID16( 800, 1004, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm130_1300_lv[] = {
ID16(1300, 1180, BUS100),
ID16(1200, 1164, BUS100),
ID16(1100, 1100, BUS100),
ID16(1000, 1020, BUS100),
ID16( 900, 1004, BUS100),
ID16( 800, 988, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm130_1300[] = {
ID16(1300, 1388, BUS100),
ID16(1200, 1356, BUS100),
ID16(1000, 1292, BUS100),
ID16( 800, 1260, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm130_1400[] = {
ID16(1400, 1484, BUS100),
ID16(1200, 1436, BUS100),
ID16(1000, 1308, BUS100),
ID16( 800, 1180, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm130_1500[] = {
ID16(1500, 1484, BUS100),
ID16(1400, 1452, BUS100),
ID16(1200, 1356, BUS100),
ID16(1000, 1228, BUS100),
ID16( 800, 1116, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm130_1600[] = {
ID16(1600, 1484, BUS100),
ID16(1400, 1420, BUS100),
ID16(1200, 1276, BUS100),
ID16(1000, 1164, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm130_1700[] = {
ID16(1700, 1484, BUS100),
ID16(1400, 1308, BUS100),
ID16(1200, 1228, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1004, BUS100),
ID16( 600, 956, BUS100),
};
static struct est_op pm90_n723[] = {
ID16(1000, 940, BUS100),
ID16( 900, 908, BUS100),
ID16( 800, 876, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n733g[] = {
ID16(1100, 956, BUS100),
ID16(1000, 940, BUS100),
ID16( 900, 908, BUS100),
ID16( 800, 876, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n733h[] = {
ID16(1100, 940, BUS100),
ID16(1000, 924, BUS100),
ID16( 900, 892, BUS100),
ID16( 800, 876, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n733i[] = {
ID16(1100, 924, BUS100),
ID16(1000, 908, BUS100),
ID16( 900, 892, BUS100),
ID16( 800, 860, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n733j[] = {
ID16(1100, 908, BUS100),
ID16(1000, 892, BUS100),
ID16( 900, 876, BUS100),
ID16( 800, 860, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n733k[] = {
ID16(1100, 892, BUS100),
ID16(1000, 876, BUS100),
ID16( 900, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n733l[] = {
ID16(1100, 876, BUS100),
ID16(1000, 876, BUS100),
ID16( 900, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n753g[] = {
ID16(1200, 956, BUS100),
ID16(1100, 940, BUS100),
ID16(1000, 908, BUS100),
ID16( 900, 892, BUS100),
ID16( 800, 860, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n753h[] = {
ID16(1200, 940, BUS100),
ID16(1100, 924, BUS100),
ID16(1000, 908, BUS100),
ID16( 900, 876, BUS100),
ID16( 800, 860, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n753i[] = {
ID16(1200, 924, BUS100),
ID16(1100, 908, BUS100),
ID16(1000, 892, BUS100),
ID16( 900, 876, BUS100),
ID16( 800, 860, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n753j[] = {
ID16(1200, 908, BUS100),
ID16(1100, 892, BUS100),
ID16(1000, 876, BUS100),
ID16( 900, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n753k[] = {
ID16(1200, 892, BUS100),
ID16(1100, 892, BUS100),
ID16(1000, 876, BUS100),
ID16( 900, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n753l[] = {
ID16(1200, 876, BUS100),
ID16(1100, 876, BUS100),
ID16(1000, 860, BUS100),
ID16( 900, 844, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n773g[] = {
ID16(1300, 956, BUS100),
ID16(1200, 940, BUS100),
ID16(1100, 924, BUS100),
ID16(1000, 908, BUS100),
ID16( 900, 876, BUS100),
ID16( 800, 860, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n773h[] = {
ID16(1300, 940, BUS100),
ID16(1200, 924, BUS100),
ID16(1100, 908, BUS100),
ID16(1000, 892, BUS100),
ID16( 900, 876, BUS100),
ID16( 800, 860, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n773i[] = {
ID16(1300, 924, BUS100),
ID16(1200, 908, BUS100),
ID16(1100, 892, BUS100),
ID16(1000, 876, BUS100),
ID16( 900, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n773j[] = {
ID16(1300, 908, BUS100),
ID16(1200, 908, BUS100),
ID16(1100, 892, BUS100),
ID16(1000, 876, BUS100),
ID16( 900, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n773k[] = {
ID16(1300, 892, BUS100),
ID16(1200, 892, BUS100),
ID16(1100, 876, BUS100),
ID16(1000, 860, BUS100),
ID16( 900, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n773l[] = {
ID16(1300, 876, BUS100),
ID16(1200, 876, BUS100),
ID16(1100, 860, BUS100),
ID16(1000, 860, BUS100),
ID16( 900, 844, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 812, BUS100),
};
static struct est_op pm90_n738[] = {
ID16(1400, 1116, BUS100),
ID16(1300, 1116, BUS100),
ID16(1200, 1100, BUS100),
ID16(1100, 1068, BUS100),
ID16(1000, 1052, BUS100),
ID16( 900, 1036, BUS100),
ID16( 800, 1020, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n758[] = {
ID16(1500, 1116, BUS100),
ID16(1400, 1116, BUS100),
ID16(1300, 1100, BUS100),
ID16(1200, 1084, BUS100),
ID16(1100, 1068, BUS100),
ID16(1000, 1052, BUS100),
ID16( 900, 1036, BUS100),
ID16( 800, 1020, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n778[] = {
ID16(1600, 1116, BUS100),
ID16(1500, 1116, BUS100),
ID16(1400, 1100, BUS100),
ID16(1300, 1184, BUS100),
ID16(1200, 1068, BUS100),
ID16(1100, 1052, BUS100),
ID16(1000, 1052, BUS100),
ID16( 900, 1036, BUS100),
ID16( 800, 1020, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n710[] = {
ID16(1400, 1340, BUS133),
ID16(1200, 1228, BUS133),
ID16(1000, 1148, BUS133),
ID16( 800, 1068, BUS133),
ID16( 600, 998, BUS133),
};
static struct est_op pm90_n715a[] = {
ID16(1500, 1340, BUS100),
ID16(1200, 1228, BUS100),
ID16(1000, 1148, BUS100),
ID16( 800, 1068, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n715b[] = {
ID16(1500, 1324, BUS100),
ID16(1200, 1212, BUS100),
ID16(1000, 1148, BUS100),
ID16( 800, 1068, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n715c[] = {
ID16(1500, 1308, BUS100),
ID16(1200, 1212, BUS100),
ID16(1000, 1132, BUS100),
ID16( 800, 1068, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n715d[] = {
ID16(1500, 1276, BUS100),
ID16(1200, 1180, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n725a[] = {
ID16(1600, 1340, BUS100),
ID16(1400, 1276, BUS100),
ID16(1200, 1212, BUS100),
ID16(1000, 1132, BUS100),
ID16( 800, 1068, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n725b[] = {
ID16(1600, 1324, BUS100),
ID16(1400, 1260, BUS100),
ID16(1200, 1196, BUS100),
ID16(1000, 1132, BUS100),
ID16( 800, 1068, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n725c[] = {
ID16(1600, 1308, BUS100),
ID16(1400, 1244, BUS100),
ID16(1200, 1180, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n725d[] = {
ID16(1600, 1276, BUS100),
ID16(1400, 1228, BUS100),
ID16(1200, 1164, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n730[] = {
ID16(1600, 1308, BUS133),
ID16(1333, 1260, BUS133),
ID16(1200, 1212, BUS133),
ID16(1067, 1180, BUS133),
ID16( 800, 988, BUS133),
};
static struct est_op pm90_n735a[] = {
ID16(1700, 1340, BUS100),
ID16(1400, 1244, BUS100),
ID16(1200, 1180, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n735b[] = {
ID16(1700, 1324, BUS100),
ID16(1400, 1244, BUS100),
ID16(1200, 1180, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n735c[] = {
ID16(1700, 1308, BUS100),
ID16(1400, 1228, BUS100),
ID16(1200, 1164, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n735d[] = {
ID16(1700, 1276, BUS100),
ID16(1400, 1212, BUS100),
ID16(1200, 1148, BUS100),
ID16(1000, 1100, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n740[] = {
ID16(1733, 1356, BUS133),
ID16(1333, 1212, BUS133),
ID16(1067, 1100, BUS133),
ID16( 800, 988, BUS133),
};
static struct est_op pm90_n745a[] = {
ID16(1800, 1340, BUS100),
ID16(1600, 1292, BUS100),
ID16(1400, 1228, BUS100),
ID16(1200, 1164, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n745b[] = {
ID16(1800, 1324, BUS100),
ID16(1600, 1276, BUS100),
ID16(1400, 1212, BUS100),
ID16(1200, 1164, BUS100),
ID16(1000, 1116, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n745c[] = {
ID16(1800, 1308, BUS100),
ID16(1600, 1260, BUS100),
ID16(1400, 1212, BUS100),
ID16(1200, 1148, BUS100),
ID16(1000, 1100, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n745d[] = {
ID16(1800, 1276, BUS100),
ID16(1600, 1228, BUS100),
ID16(1400, 1180, BUS100),
ID16(1200, 1132, BUS100),
ID16(1000, 1084, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n750[] = {
ID16(1867, 1308, BUS133),
ID16(1600, 1228, BUS133),
ID16(1333, 1148, BUS133),
ID16(1067, 1068, BUS133),
ID16( 800, 988, BUS133),
};
static struct est_op pm90_n755a[] = {
ID16(2000, 1340, BUS100),
ID16(1800, 1292, BUS100),
ID16(1600, 1244, BUS100),
ID16(1400, 1196, BUS100),
ID16(1200, 1148, BUS100),
ID16(1000, 1100, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n755b[] = {
ID16(2000, 1324, BUS100),
ID16(1800, 1276, BUS100),
ID16(1600, 1228, BUS100),
ID16(1400, 1180, BUS100),
ID16(1200, 1132, BUS100),
ID16(1000, 1084, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n755c[] = {
ID16(2000, 1308, BUS100),
ID16(1800, 1276, BUS100),
ID16(1600, 1228, BUS100),
ID16(1400, 1180, BUS100),
ID16(1200, 1132, BUS100),
ID16(1000, 1084, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n755d[] = {
ID16(2000, 1276, BUS100),
ID16(1800, 1244, BUS100),
ID16(1600, 1196, BUS100),
ID16(1400, 1164, BUS100),
ID16(1200, 1116, BUS100),
ID16(1000, 1084, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n760[] = {
ID16(2000, 1356, BUS133),
ID16(1600, 1244, BUS133),
ID16(1333, 1164, BUS133),
ID16(1067, 1084, BUS133),
ID16( 800, 988, BUS133),
};
static struct est_op pm90_n765a[] = {
ID16(2100, 1340, BUS100),
ID16(1800, 1276, BUS100),
ID16(1600, 1228, BUS100),
ID16(1400, 1180, BUS100),
ID16(1200, 1132, BUS100),
ID16(1000, 1084, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n765b[] = {
ID16(2100, 1324, BUS100),
ID16(1800, 1260, BUS100),
ID16(1600, 1212, BUS100),
ID16(1400, 1180, BUS100),
ID16(1200, 1132, BUS100),
ID16(1000, 1084, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n765c[] = {
ID16(2100, 1308, BUS100),
ID16(1800, 1244, BUS100),
ID16(1600, 1212, BUS100),
ID16(1400, 1164, BUS100),
ID16(1200, 1116, BUS100),
ID16(1000, 1084, BUS100),
ID16( 800, 1036, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n765e[] = {
ID16(2100, 1356, BUS100),
ID16(1800, 1292, BUS100),
ID16(1600, 1244, BUS100),
ID16(1400, 1196, BUS100),
ID16(1200, 1148, BUS100),
ID16(1000, 1100, BUS100),
ID16( 800, 1052, BUS100),
ID16( 600, 988, BUS100),
};
static struct est_op pm90_n770[] = {
ID16(2133, 1356, BUS133),
ID16(1867, 1292, BUS133),
ID16(1600, 1212, BUS133),
ID16(1333, 1148, BUS133),
ID16(1067, 1068, BUS133),
ID16( 800, 988, BUS133),
};
static struct est_op C7M_770_ULV[] = {
ID16(1000, 844, BUS100),
ID16( 800, 796, BUS100),
ID16( 600, 796, BUS100),
ID16( 400, 796, BUS100),
};
static struct est_op C7M_779_ULV[] = {
ID16(1000, 796, BUS100),
ID16( 800, 796, BUS100),
ID16( 600, 796, BUS100),
ID16( 400, 796, BUS100),
};
static struct est_op C7M_772_ULV[] = {
ID16(1200, 844, BUS100),
ID16(1000, 844, BUS100),
ID16( 800, 828, BUS100),
ID16( 600, 796, BUS100),
ID16( 400, 796, BUS100),
};
static struct est_op C7M_775_ULV[] = {
ID16(1500, 956, BUS100),
ID16(1400, 940, BUS100),
ID16(1000, 860, BUS100),
ID16( 800, 828, BUS100),
ID16( 600, 796, BUS100),
ID16( 400, 796, BUS100),
};
static struct est_op C7M_771[] = {
ID16(1200, 860, BUS100),
ID16(1000, 860, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 844, BUS100),
ID16( 400, 844, BUS100),
};
static struct est_op C7M_754[] = {
ID16(1500, 1004, BUS100),
ID16(1400, 988, BUS100),
ID16(1000, 940, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 844, BUS100),
ID16( 400, 844, BUS100),
};
static struct est_op C7M_764[] = {
ID16(1600, 1084, BUS100),
ID16(1400, 1052, BUS100),
ID16(1000, 1004, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 844, BUS100),
ID16( 400, 844, BUS100),
};
static struct est_op C7M_784[] = {
ID16(1800, 1148, BUS100),
ID16(1600, 1100, BUS100),
ID16(1400, 1052, BUS100),
ID16(1000, 1004, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 844, BUS100),
ID16( 400, 844, BUS100),
};
static struct est_op C7M_794[] = {
ID16(2000, 1148, BUS100),
ID16(1800, 1132, BUS100),
ID16(1600, 1100, BUS100),
ID16(1400, 1052, BUS100),
ID16(1000, 1004, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 844, BUS100),
ID16( 400, 844, BUS100),
};
static struct est_op C7M_765[] = {
ID16(1600, 1084, BUS133),
ID16(1467, 1052, BUS133),
ID16(1200, 1004, BUS133),
ID16( 800, 844, BUS133),
ID16( 667, 844, BUS133),
ID16( 533, 844, BUS133),
};
static struct est_op C7M_785[] = {
ID16(1867, 1148, BUS133),
ID16(1600, 1100, BUS133),
ID16(1467, 1052, BUS133),
ID16(1200, 1004, BUS133),
ID16( 800, 844, BUS133),
ID16( 667, 844, BUS133),
ID16( 533, 844, BUS133),
};
static struct est_op C7M_795[] = {
ID16(2000, 1148, BUS133),
ID16(1867, 1132, BUS133),
ID16(1600, 1100, BUS133),
ID16(1467, 1052, BUS133),
ID16(1200, 1004, BUS133),
ID16( 800, 844, BUS133),
ID16( 667, 844, BUS133),
ID16( 533, 844, BUS133),
};
static struct est_op eden90_1000[] = {
ID16(1000, 844, BUS100),
ID16( 800, 844, BUS100),
ID16( 600, 844, BUS100),
ID16( 400, 844, BUS100),
};
struct fqlist {
int vendor: 5;
unsigned bus_clk : 1;
unsigned n : 5;
struct est_op *table;
};
#define ENTRY(ven, bus_clk, tab) \
{ CPUVENDOR_##ven, bus_clk == BUS133 ? 1 : 0, nitems(tab), tab }
#define BUS_CLK(fqp) ((fqp)->bus_clk ? BUS133 : BUS100)
static struct fqlist est_cpus[] = {
ENTRY(INTEL, BUS100, pm130_900_ulv),
ENTRY(INTEL, BUS100, pm130_1000_ulv),
ENTRY(INTEL, BUS100, pm130_1100_ulv),
ENTRY(INTEL, BUS100, pm130_1100_lv),
ENTRY(INTEL, BUS100, pm130_1200_lv),
ENTRY(INTEL, BUS100, pm130_1300_lv),
ENTRY(INTEL, BUS100, pm130_1300),
ENTRY(INTEL, BUS100, pm130_1400),
ENTRY(INTEL, BUS100, pm130_1500),
ENTRY(INTEL, BUS100, pm130_1600),
ENTRY(INTEL, BUS100, pm130_1700),
ENTRY(INTEL, BUS100, pm90_n723),
ENTRY(INTEL, BUS100, pm90_n733g),
ENTRY(INTEL, BUS100, pm90_n733h),
ENTRY(INTEL, BUS100, pm90_n733i),
ENTRY(INTEL, BUS100, pm90_n733j),
ENTRY(INTEL, BUS100, pm90_n733k),
ENTRY(INTEL, BUS100, pm90_n733l),
ENTRY(INTEL, BUS100, pm90_n753g),
ENTRY(INTEL, BUS100, pm90_n753h),
ENTRY(INTEL, BUS100, pm90_n753i),
ENTRY(INTEL, BUS100, pm90_n753j),
ENTRY(INTEL, BUS100, pm90_n753k),
ENTRY(INTEL, BUS100, pm90_n753l),
ENTRY(INTEL, BUS100, pm90_n773g),
ENTRY(INTEL, BUS100, pm90_n773h),
ENTRY(INTEL, BUS100, pm90_n773i),
ENTRY(INTEL, BUS100, pm90_n773j),
ENTRY(INTEL, BUS100, pm90_n773k),
ENTRY(INTEL, BUS100, pm90_n773l),
ENTRY(INTEL, BUS100, pm90_n738),
ENTRY(INTEL, BUS100, pm90_n758),
ENTRY(INTEL, BUS100, pm90_n778),
ENTRY(INTEL, BUS133, pm90_n710),
ENTRY(INTEL, BUS100, pm90_n715a),
ENTRY(INTEL, BUS100, pm90_n715b),
ENTRY(INTEL, BUS100, pm90_n715c),
ENTRY(INTEL, BUS100, pm90_n715d),
ENTRY(INTEL, BUS100, pm90_n725a),
ENTRY(INTEL, BUS100, pm90_n725b),
ENTRY(INTEL, BUS100, pm90_n725c),
ENTRY(INTEL, BUS100, pm90_n725d),
ENTRY(INTEL, BUS133, pm90_n730),
ENTRY(INTEL, BUS100, pm90_n735a),
ENTRY(INTEL, BUS100, pm90_n735b),
ENTRY(INTEL, BUS100, pm90_n735c),
ENTRY(INTEL, BUS100, pm90_n735d),
ENTRY(INTEL, BUS133, pm90_n740),
ENTRY(INTEL, BUS100, pm90_n745a),
ENTRY(INTEL, BUS100, pm90_n745b),
ENTRY(INTEL, BUS100, pm90_n745c),
ENTRY(INTEL, BUS100, pm90_n745d),
ENTRY(INTEL, BUS133, pm90_n750),
ENTRY(INTEL, BUS100, pm90_n755a),
ENTRY(INTEL, BUS100, pm90_n755b),
ENTRY(INTEL, BUS100, pm90_n755c),
ENTRY(INTEL, BUS100, pm90_n755d),
ENTRY(INTEL, BUS133, pm90_n760),
ENTRY(INTEL, BUS100, pm90_n765a),
ENTRY(INTEL, BUS100, pm90_n765b),
ENTRY(INTEL, BUS100, pm90_n765c),
ENTRY(INTEL, BUS100, pm90_n765e),
ENTRY(INTEL, BUS133, pm90_n770),
ENTRY(VIA, BUS100, C7M_770_ULV),
ENTRY(VIA, BUS100, C7M_779_ULV),
ENTRY(VIA, BUS100, C7M_772_ULV),
ENTRY(VIA, BUS100, C7M_771),
ENTRY(VIA, BUS100, C7M_775_ULV),
ENTRY(VIA, BUS100, C7M_754),
ENTRY(VIA, BUS100, C7M_764),
ENTRY(VIA, BUS133, C7M_765),
ENTRY(VIA, BUS100, C7M_784),
ENTRY(VIA, BUS133, C7M_785),
ENTRY(VIA, BUS100, C7M_794),
ENTRY(VIA, BUS133, C7M_795),
ENTRY(VIA, BUS100, eden90_1000),
};
#define MSR2MHZ(msr, bus) \
(((((int) (msr) >> 8) & 0xff) * (bus) + 50) / 100)
#define MSR2MV(msr) \
(((int) (msr) & 0xff) * 16 + 700)
static struct fqlist *est_fqlist;
extern int setperf_prio;
extern int perflevel;
void p4_get_bus_clock(struct cpu_info *);
void p3_get_bus_clock(struct cpu_info *);
void cyrix3_get_bus_clock(struct cpu_info *);
#if NACPICPU > 0
struct fqlist * est_acpi_init(void);
void est_acpi_pss_changed(struct acpicpu_pss *, int);
struct fqlist *
est_acpi_init(void)
{
struct acpicpu_pss *pss;
struct fqlist *acpilist;
int nstates, i;
int high, low;
if ((nstates = acpicpu_fetch_pss(&pss)) == 0)
goto nolist;
high = pss[0].pss_core_freq;
low = pss[nstates - 1].pss_core_freq;
if (high - low <= 0)
goto nolist;
if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
== NULL)
goto nolist;
if ((acpilist->table = mallocarray(nstates, sizeof(struct est_op),
M_DEVBUF, M_NOWAIT)) == NULL)
goto notable;
acpilist->n = nstates;
for (i = 0; i < nstates; i++) {
acpilist->table[i].mhz = pss[i].pss_core_freq;
acpilist->table[i].ctrl = pss[i].pss_ctrl;
acpilist->table[i].pct =
(pss[i].pss_core_freq - low) * 100 / (high - low);
}
acpicpu_set_notify(est_acpi_pss_changed);
return acpilist;
notable:
free(acpilist, M_DEVBUF, sizeof(*acpilist));
acpilist = NULL;
nolist:
return NULL;
}
void
est_acpi_pss_changed(struct acpicpu_pss *pss, int npss)
{
struct fqlist *acpilist;
int needtran = 1, i;
int high, low;
u_int64_t msr;
u_int16_t cur;
msr = rdmsr(MSR_PERF_STATUS);
cur = msr & 0xffff;
high = pss[0].pss_core_freq;
low = pss[npss - 1].pss_core_freq;
if (high - low <= 0) {
printf("est_acpi_pss_changed: new est state has no "
"speed step\n");
return;
}
if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
== NULL) {
printf("est_acpi_pss_changed: cannot allocate memory for new "
"est state\n");
return;
}
if ((acpilist->table = mallocarray(npss, sizeof(struct est_op),
M_DEVBUF, M_NOWAIT)) == NULL) {
printf("est_acpi_pss_changed: cannot allocate memory for new "
"operating points\n");
free(acpilist, M_DEVBUF, sizeof(*acpilist));
return;
}
for (i = 0; i < npss; i++) {
acpilist->table[i].mhz = pss[i].pss_core_freq;
acpilist->table[i].ctrl = pss[i].pss_ctrl;
acpilist->table[i].pct =
(pss[i].pss_core_freq - low) * 100 / (high - low);
if (pss[i].pss_ctrl == cur)
needtran = 0;
}
free(est_fqlist->table, M_DEVBUF, npss * sizeof(struct est_op));
free(est_fqlist, M_DEVBUF, sizeof *est_fqlist);
est_fqlist = acpilist;
if (needtran) {
est_setperf(perflevel);
}
}
#endif
void
est_init(struct cpu_info *ci, int vendor)
{
const char *cpu_device = ci->ci_dev->dv_xname;
int i, low, high;
u_int64_t msr;
u_int16_t idhi, idlo, cur;
u_int8_t crhi, crlo, crcur;
struct fqlist *fql;
struct fqlist *fake_fqlist;
struct est_op *fake_table;
if (setperf_prio > 3)
return;
#if NACPICPU > 0
est_fqlist = est_acpi_init();
#endif
if (est_fqlist == NULL) {
if (vendor == CPUVENDOR_VIA)
cyrix3_get_bus_clock(ci);
else if (ci->ci_family == 0xf)
p4_get_bus_clock(ci);
else if (ci->ci_family == 6)
p3_get_bus_clock(ci);
}
if (est_fqlist == NULL && bus_clock != 0) {
msr = rdmsr(MSR_PERF_STATUS);
idhi = (msr >> 32) & 0xffff;
idlo = (msr >> 48) & 0xffff;
cur = msr & 0xffff;
crhi = (idhi >> 8) & 0xff;
crlo = (idlo >> 8) & 0xff;
crcur = (cur >> 8) & 0xff;
for (i = 0; i < nitems(est_cpus); i++) {
fql = &est_cpus[i];
if (vendor == fql->vendor && bus_clock == BUS_CLK(fql)
&& idhi == fql->table[0].ctrl
&& idlo == fql->table[fql->n - 1].ctrl) {
est_fqlist = fql;
break;
}
}
}
if (est_fqlist == NULL && bus_clock != 0) {
if (crhi == 0 || crcur == 0 || crlo > crhi ||
crcur < crlo || crcur > crhi) {
printf("%s: EST: strange msr value 0x%016llx\n",
cpu_device, msr);
return;
}
if (crlo == 0 || crhi == crlo) {
return;
}
printf("%s: unknown Enhanced SpeedStep CPU, msr 0x%016llx\n",
cpu_device, msr);
if ((fake_fqlist = malloc(sizeof(struct fqlist), M_DEVBUF,
M_NOWAIT)) == NULL) {
printf("%s: EST: cannot allocate memory for fake "
"list\n", cpu_device);
return;
}
if ((fake_table = mallocarray(3, sizeof(struct est_op),
M_DEVBUF, M_NOWAIT)) == NULL) {
free(fake_fqlist, M_DEVBUF, sizeof(struct fqlist));
printf("%s: EST: cannot allocate memory for fake "
"table\n", cpu_device);
return;
}
fake_table[0].ctrl = idhi;
fake_table[0].mhz = MSR2MHZ(idhi, bus_clock);
if (cur == idhi || cur == idlo) {
printf("%s: using only highest and lowest power "
"states\n", cpu_device);
fake_table[0].pct = 51;
fake_table[1].ctrl = idlo;
fake_table[1].mhz = MSR2MHZ(idlo, bus_clock);
fake_table[1].pct = 0;
fake_fqlist->n = 2;
} else {
printf("%s: using only highest, current and lowest "
"power states\n", cpu_device);
fake_table[0].pct = 67;
fake_table[1].ctrl = cur;
fake_table[1].mhz = MSR2MHZ(cur, bus_clock);
fake_table[1].pct = 34;
fake_table[2].ctrl = idlo;
fake_table[2].mhz = MSR2MHZ(idlo, bus_clock);
fake_table[2].pct = 0;
fake_fqlist->n = 3;
}
fake_fqlist->vendor = vendor;
fake_fqlist->table = fake_table;
est_fqlist = fake_fqlist;
}
if (est_fqlist == NULL)
return;
if (est_fqlist->n < 2)
goto nospeedstep;
low = est_fqlist->table[est_fqlist->n - 1].mhz;
high = est_fqlist->table[0].mhz;
if (low == high)
goto nospeedstep;
perflevel = (cpuspeed - low) * 100 / (high - low);
printf("%s: Enhanced SpeedStep %d MHz", cpu_device, cpuspeed);
printf(": speeds: ");
for (i = 0; i < est_fqlist->n; i++)
printf("%d%s", est_fqlist->table[i].mhz, i < est_fqlist->n - 1
? ", " : " MHz\n");
cpu_setperf = est_setperf;
setperf_prio = 3;
return;
nospeedstep:
free(est_fqlist->table, M_DEVBUF, 0);
free(est_fqlist, M_DEVBUF, sizeof(*est_fqlist));
}
void
est_setperf(int level)
{
int i;
uint64_t msr;
if (est_fqlist == NULL)
return;
for (i = 0; i < est_fqlist->n; i++) {
if (level >= est_fqlist->table[i].pct)
break;
}
msr = rdmsr(MSR_PERF_CTL);
msr &= ~0xffffULL;
msr |= est_fqlist->table[i].ctrl;
wrmsr(MSR_PERF_CTL, msr);
cpuspeed = est_fqlist->table[i].mhz;
}