mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
cpufreq: intel_pstate: Request P-states control from SMM if needed
Currently, intel_pstate is unable to control P-states on my IvyBridge-based Acer Aspire S5, because they are controlled by SMM on that machine by default and it is necessary to request OS control of P-states from it via the SMI Command register exposed in the ACPI FADT. intel_pstate doesn't do that now, but acpi-cpufreq and other cpufreq drivers for x86 platforms do. Address this problem by making intel_pstate use the ACPI-defined mechanism as well. However, intel_pstate is not modular and it doesn't need the module refcount tricks played by acpi_processor_notify_smm(), so export the core of this function to it as acpi_processor_pstate_control() and make it call that. [The changes in processor_perflib.c related to this should not make any functional difference for the acpi_processor_notify_smm() users]. To be safe, only call acpi_processor_notify_smm() from intel_pstate if ACPI _PPC support is enabled in it. Suggested-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
This commit is contained in:
parent
f0da898b46
commit
d0ea59e188
3 changed files with 42 additions and 17 deletions
|
@ -465,11 +465,33 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_processor_get_performance_info);
|
EXPORT_SYMBOL_GPL(acpi_processor_get_performance_info);
|
||||||
int acpi_processor_notify_smm(struct module *calling_module)
|
|
||||||
|
int acpi_processor_pstate_control(void)
|
||||||
{
|
{
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
static int is_done = 0;
|
|
||||||
|
|
||||||
|
if (!acpi_gbl_FADT.smi_command || !acpi_gbl_FADT.pstate_control)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||||
|
"Writing pstate_control [0x%x] to smi_command [0x%x]\n",
|
||||||
|
acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
|
||||||
|
|
||||||
|
status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
|
||||||
|
(u32)acpi_gbl_FADT.pstate_control, 8);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
ACPI_EXCEPTION((AE_INFO, status,
|
||||||
|
"Failed to write pstate_control [0x%x] to smi_command [0x%x]",
|
||||||
|
acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
int acpi_processor_notify_smm(struct module *calling_module)
|
||||||
|
{
|
||||||
|
static int is_done = 0;
|
||||||
|
int result;
|
||||||
|
|
||||||
if (!(acpi_processor_ppc_status & PPC_REGISTERED))
|
if (!(acpi_processor_ppc_status & PPC_REGISTERED))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -492,26 +514,15 @@ int acpi_processor_notify_smm(struct module *calling_module)
|
||||||
|
|
||||||
is_done = -EIO;
|
is_done = -EIO;
|
||||||
|
|
||||||
/* Can't write pstate_control to smi_command if either value is zero */
|
result = acpi_processor_pstate_control();
|
||||||
if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
|
if (!result) {
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
|
||||||
module_put(calling_module);
|
module_put(calling_module);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (result < 0) {
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
|
||||||
"Writing pstate_control [0x%x] to smi_command [0x%x]\n",
|
|
||||||
acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
|
|
||||||
|
|
||||||
status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
|
|
||||||
(u32) acpi_gbl_FADT.pstate_control, 8);
|
|
||||||
if (ACPI_FAILURE(status)) {
|
|
||||||
ACPI_EXCEPTION((AE_INFO, status,
|
|
||||||
"Failed to write pstate_control [0x%x] to "
|
|
||||||
"smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
|
|
||||||
acpi_gbl_FADT.smi_command));
|
|
||||||
module_put(calling_module);
|
module_put(calling_module);
|
||||||
return status;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Success. If there's no _PPC, we need to fear nothing, so
|
/* Success. If there's no _PPC, we need to fear nothing, so
|
||||||
|
|
|
@ -1909,9 +1909,20 @@ static bool __init intel_pstate_platform_pwr_mgmt_exists(void)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void intel_pstate_request_control_from_smm(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* It may be unsafe to request P-states control from SMM if _PPC support
|
||||||
|
* has not been enabled.
|
||||||
|
*/
|
||||||
|
if (acpi_ppc)
|
||||||
|
acpi_processor_pstate_control();
|
||||||
|
}
|
||||||
#else /* CONFIG_ACPI not enabled */
|
#else /* CONFIG_ACPI not enabled */
|
||||||
static inline bool intel_pstate_platform_pwr_mgmt_exists(void) { return false; }
|
static inline bool intel_pstate_platform_pwr_mgmt_exists(void) { return false; }
|
||||||
static inline bool intel_pstate_has_acpi_ppc(void) { return false; }
|
static inline bool intel_pstate_has_acpi_ppc(void) { return false; }
|
||||||
|
static inline void intel_pstate_request_control_from_smm(void) {}
|
||||||
#endif /* CONFIG_ACPI */
|
#endif /* CONFIG_ACPI */
|
||||||
|
|
||||||
static const struct x86_cpu_id hwp_support_ids[] __initconst = {
|
static const struct x86_cpu_id hwp_support_ids[] __initconst = {
|
||||||
|
@ -1963,6 +1974,8 @@ static int __init intel_pstate_init(void)
|
||||||
if (!hwp_active && hwp_only)
|
if (!hwp_active && hwp_only)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
intel_pstate_request_control_from_smm();
|
||||||
|
|
||||||
rc = cpufreq_register_driver(&intel_pstate_driver);
|
rc = cpufreq_register_driver(&intel_pstate_driver);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -249,6 +249,7 @@ extern int acpi_processor_register_performance(struct acpi_processor_performance
|
||||||
*performance, unsigned int cpu);
|
*performance, unsigned int cpu);
|
||||||
extern void acpi_processor_unregister_performance(unsigned int cpu);
|
extern void acpi_processor_unregister_performance(unsigned int cpu);
|
||||||
|
|
||||||
|
int acpi_processor_pstate_control(void);
|
||||||
/* note: this locks both the calling module and the processor module
|
/* note: this locks both the calling module and the processor module
|
||||||
if a _PPC object exists, rmmod is disallowed then */
|
if a _PPC object exists, rmmod is disallowed then */
|
||||||
int acpi_processor_notify_smm(struct module *calling_module);
|
int acpi_processor_notify_smm(struct module *calling_module);
|
||||||
|
|
Loading…
Reference in a new issue