// SPDX-License-Identifier: GPL-2.0-only /* * Based on documentation provided by Dave Jones. Thanks! * * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/
/* Minimum necessary to get acpi_processor_get_bios_limit() working */ staticint eps_acpi_init(void)
{
eps_acpi_cpu_perf = kzalloc(sizeof(*eps_acpi_cpu_perf),
GFP_KERNEL); if (!eps_acpi_cpu_perf) return -ENOMEM;
/* Wait while CPU is busy */
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i = 0; while (lo & ((1 << 16) | (1 << 17))) {
udelay(16);
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i++; if (unlikely(i > 64)) { return -ENODEV;
}
} /* Set new multiplier and voltage */
wrmsr(MSR_IA32_PERF_CTL, dest_state & 0xffff, 0); /* Wait until transition end */
i = 0; do {
udelay(16);
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i++; if (unlikely(i > 64)) { return -ENODEV;
}
} while (lo & ((1 << 16) | (1 << 17)));
/* Check for systems using underclocked CPU */ if (!freq_failsafe_off && max_multiplier != current_multiplier) {
pr_info("Your processor is running at different frequency then its maximum. Aborting.\n");
pr_info("You can use freq_failsafe_off option to disable this check.\n"); return -EINVAL;
} if (!voltage_failsafe_off && max_voltage != current_voltage) {
pr_info("Your processor is running at different voltage then its maximum. Aborting.\n");
pr_info("You can use voltage_failsafe_off option to disable this check.\n"); return -EINVAL;
}
#if IS_ENABLED(CONFIG_ACPI_PROCESSOR) /* Check for ACPI processor speed limit */ if (!ignore_acpi_limit && !eps_acpi_init()) { if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) {
pr_info("ACPI limit %u.%uGHz\n",
limit/1000000,
(limit%1000000)/10000);
eps_acpi_exit(policy); /* Check if max_multiplier is in BIOS limits */ if (limit && max_multiplier * fsb > limit) {
pr_info("Aborting\n"); return -EINVAL;
}
}
} #endif
/* Allow user to set lower maximum voltage then that reported
* by processor */ if (brand == EPS_BRAND_C7M && set_max_voltage) {
u32 v;
/* Change mV to something hardware can use */
v = (set_max_voltage - 700) / 16; /* Check if voltage is within limits */ if (v >= min_voltage && v <= max_voltage) {
pr_info("Setting %dmV as maximum\n", v * 16 + 700);
max_voltage = v;
}
}
/* Calc number of p-states supported */ if (brand == EPS_BRAND_C7M)
states = max_multiplier - min_multiplier + 1; else
states = 2;
/* Allocate private data and frequency table for current cpu */
centaur = kzalloc(struct_size(centaur, freq_table, states + 1),
GFP_KERNEL); if (!centaur) return -ENOMEM;
eps_cpu[0] = centaur;
/* This driver will work only on Centaur C7 processors with
* Enhanced SpeedStep/PowerSaver registers */ staticconststruct x86_cpu_id eps_cpu_id[] = {
X86_MATCH_VENDOR_FAM_FEATURE(CENTAUR, 6, X86_FEATURE_EST, NULL),
{}
};
MODULE_DEVICE_TABLE(x86cpu, eps_cpu_id);
staticint __init eps_init(void)
{ if (!x86_match_cpu(eps_cpu_id) || boot_cpu_data.x86_model < 10) return -ENODEV; if (cpufreq_register_driver(&eps_driver)) return -EINVAL; return 0;
}
/* Allow user to overclock his machine or to change frequency to higher after
* unloading module */
module_param(freq_failsafe_off, int, 0644);
MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check");
module_param(voltage_failsafe_off, int, 0644);
MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check"); #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
module_param(ignore_acpi_limit, int, 0644);
MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit"); #endif
module_param(set_max_voltage, int, 0644);
MODULE_PARM_DESC(set_max_voltage, "Set maximum CPU voltage (mV) C7-M only");
MODULE_AUTHOR("Rafal Bilski ");
MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
MODULE_LICENSE("GPL");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.