summaryrefslogtreecommitdiff
path: root/drivers/acpi/processor.c
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2004-10-08 08:55:44 -0400
committerLen Brown <lenb@dhcppc3.>2004-10-08 08:55:44 -0400
commit74245ae77995707df10ebc4aba2e8074dd99626f (patch)
tree895d5006ebbe606cad5830c0ad0435f17b5cd1b0 /drivers/acpi/processor.c
parentf2493ff8e27a501063d270a2c6089295c77c73fc (diff)
[ACPI] Notify SMM of cpufreq
http://marc.theaimsgroup.com/?l=acpi4linux&m=109428989121089&w=2 Signed-off-by: Dominik Brodowski <linux@brodo.de>
Diffstat (limited to 'drivers/acpi/processor.c')
-rw-r--r--drivers/acpi/processor.c87
1 files changed, 79 insertions, 8 deletions
diff --git a/drivers/acpi/processor.c b/drivers/acpi/processor.c
index 83fb743aa3e7..f55b23e0ecfa 100644
--- a/drivers/acpi/processor.c
+++ b/drivers/acpi/processor.c
@@ -762,7 +762,10 @@ static DECLARE_MUTEX(performance_sem);
* policy is adjusted accordingly.
*/
-static int acpi_processor_ppc_is_init = 0;
+#define PPC_REGISTERED 1
+#define PPC_IN_USE 2
+
+static int acpi_processor_ppc_status = 0;
static int acpi_processor_ppc_notifier(struct notifier_block *nb,
unsigned long event,
@@ -820,6 +823,10 @@ acpi_processor_get_platform_limit (
* (e.g. 0 = states 0..n; 1 = states 1..n; etc.
*/
status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
+
+ if (status != AE_NOT_FOUND)
+ acpi_processor_ppc_status |= PPC_IN_USE;
+
if(ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PPC\n"));
return_VALUE(-ENODEV);
@@ -844,17 +851,17 @@ static int acpi_processor_ppc_has_changed(
static void acpi_processor_ppc_init(void) {
if (!cpufreq_register_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER))
- acpi_processor_ppc_is_init = 1;
+ acpi_processor_ppc_status |= PPC_REGISTERED;
else
printk(KERN_DEBUG "Warning: Processor Platform Limit not supported.\n");
}
static void acpi_processor_ppc_exit(void) {
- if (acpi_processor_ppc_is_init)
+ if (acpi_processor_ppc_status & PPC_REGISTERED)
cpufreq_unregister_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER);
- acpi_processor_ppc_is_init = 0;
+ acpi_processor_ppc_status &= ~PPC_REGISTERED;
}
/*
@@ -1074,6 +1081,73 @@ acpi_processor_get_performance_info (
}
+int acpi_processor_notify_smm(struct module *calling_module) {
+ acpi_status status;
+ static int is_done = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_notify_smm");
+
+ if (!(acpi_processor_ppc_status & PPC_REGISTERED))
+ return_VALUE(-EBUSY);
+
+ if (!try_module_get(calling_module))
+ return_VALUE(-EINVAL);
+
+ /* is_done is set to negative if an error occured,
+ * and to postitive if _no_ error occured, but SMM
+ * was already notified. This avoids double notification
+ * which might lead to unexpected results...
+ */
+ if (is_done > 0) {
+ module_put(calling_module);
+ return_VALUE(0);
+ }
+ else if (is_done < 0) {
+ module_put(calling_module);
+ return_VALUE(is_done);
+ }
+
+ is_done = -EIO;
+
+ /* Can't write pstate_cnt to smi_cmd if either value is zero */
+ if ((!acpi_fadt.smi_cmd) ||
+ (!acpi_fadt.pstate_cnt)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No SMI port or pstate_cnt\n"));
+ module_put(calling_module);
+ return_VALUE(0);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n", acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+
+ /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
+ * it anyway, so we need to support it... */
+ if (acpi_fadt_is_v1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Using v1.0 FADT reserved value for pstate_cnt\n"));
+ }
+
+ status = acpi_os_write_port (acpi_fadt.smi_cmd,
+ (u32) acpi_fadt.pstate_cnt, 8);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Failed to write pstate_cnt [0x%x] to "
+ "smi_cmd [0x%x]\n", acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+ module_put(calling_module);
+ return_VALUE(status);
+ }
+
+ /* Success. If there's no _PPC, we need to fear nothing, so
+ * we can allow the cpufreq driver to be rmmod'ed. */
+ is_done = 1;
+
+ if (!(acpi_processor_ppc_status & PPC_IN_USE))
+ module_put(calling_module);
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_processor_notify_smm);
+
+
#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
/* /proc/acpi/processor/../performance interface (DEPRECATED) */
@@ -1230,7 +1304,7 @@ acpi_processor_register_performance (
ACPI_FUNCTION_TRACE("acpi_processor_register_performance");
- if (!acpi_processor_ppc_is_init)
+ if (!(acpi_processor_ppc_status & PPC_REGISTERED))
return_VALUE(-EINVAL);
down(&performance_sem);
@@ -1271,9 +1345,6 @@ acpi_processor_unregister_performance (
ACPI_FUNCTION_TRACE("acpi_processor_unregister_performance");
- if (!acpi_processor_ppc_is_init)
- return_VOID;
-
down(&performance_sem);
pr = processors[cpu];