aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-11-17 22:47:47 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-11-17 22:47:47 +0100
commitd0ea59e188941417a9fb5898d894b3106a8ad313 (patch)
treea5fdde28c81123f3221ca699914e8917441e6cd6
parentf0da898b464953157911913cd93eaedcb2c92407 (diff)
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>
-rw-r--r--drivers/acpi/processor_perflib.c45
-rw-r--r--drivers/cpufreq/intel_pstate.c13
-rw-r--r--include/acpi/processor.h1
3 files changed, 42 insertions, 17 deletions
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index bb01dea39fdc..9c67faa034b5 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -465,11 +465,33 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr)
return result;
}
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;
- 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))
return -EBUSY;
@@ -492,26 +514,15 @@ int acpi_processor_notify_smm(struct module *calling_module)
is_done = -EIO;
- /* Can't write pstate_control to smi_command if either value is zero */
- if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
+ result = acpi_processor_pstate_control();
+ if (!result) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
module_put(calling_module);
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_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));
+ if (result < 0) {
module_put(calling_module);
- return status;
+ return result;
}
/* Success. If there's no _PPC, we need to fear nothing, so
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index f07e591c0e1f..ec1664bf6ef0 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -1909,9 +1909,20 @@ static bool __init intel_pstate_platform_pwr_mgmt_exists(void)
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 */
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 void intel_pstate_request_control_from_smm(void) {}
#endif /* CONFIG_ACPI */
static const struct x86_cpu_id hwp_support_ids[] __initconst = {
@@ -1963,6 +1974,8 @@ hwp_cpu_matched:
if (!hwp_active && hwp_only)
goto out;
+ intel_pstate_request_control_from_smm();
+
rc = cpufreq_register_driver(&intel_pstate_driver);
if (rc)
goto out;
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index f3db11c24654..dd0cb04046ce 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -249,6 +249,7 @@ extern int acpi_processor_register_performance(struct acpi_processor_performance
*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
if a _PPC object exists, rmmod is disallowed then */
int acpi_processor_notify_smm(struct module *calling_module);