diff mbox

[RFC] ACPI: support overriding an ACPI control method at runtime

Message ID 1259139678.10510.59.camel@rzhang1-desktop (mailing list archive)
State Accepted
Headers show

Commit Message

Zhang Rui Nov. 25, 2009, 9:01 a.m. UTC
None
diff mbox

Patch

Index: linux-2.6/drivers/acpi/debug.c
===================================================================
--- linux-2.6.orig/drivers/acpi/debug.c
+++ linux-2.6/drivers/acpi/debug.c
@@ -8,6 +8,7 @@ 
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/moduleparam.h>
+#include <linux/debugfs.h>
 #include <asm/uaccess.h>
 #include <acpi/acpi_drivers.h>
 
@@ -196,6 +197,79 @@  module_param_call(trace_state, param_set
 		  NULL, 0644);
 
 /* --------------------------------------------------------------------------
+				DebugFS Interface
+   -------------------------------------------------------------------------- */
+
+static ssize_t cm_write(struct file *file, const char __user *user_buf,
+			size_t count, loff_t *ppos)
+{
+	static char *buf;
+	static int uncopied_bytes;
+	struct acpi_table_header table;
+	acpi_status status;
+
+	if (!(*ppos)) {
+		/* parse the table header to get the table length */
+		if (count <= sizeof(struct acpi_table_header))
+			return -EINVAL;
+		if (copy_from_user(&table, user_buf,
+			sizeof(struct acpi_table_header)))
+			return -EFAULT;
+		uncopied_bytes = table.length;
+		buf = kzalloc(uncopied_bytes, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+	}
+
+	if (uncopied_bytes < count) {
+		kfree(buf);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(buf + (*ppos), user_buf, count)) {
+		kfree(buf);
+		return -EFAULT;
+	}
+
+	uncopied_bytes -= count;
+	*ppos += count;
+
+	if (!uncopied_bytes) {
+		status = acpi_install_method(buf);
+		kfree(buf);
+		if (ACPI_FAILURE(status))
+			return -EINVAL;
+	}
+
+	return count;
+}
+
+static const struct file_operations cm_fops = {
+	.write = cm_write,
+};
+
+static int acpi_debugfs_init(void)
+{
+	struct dentry *acpi_dir, *cm_dentry;
+
+	acpi_dir = debugfs_create_dir("acpi", NULL);
+	if (!acpi_dir)
+		goto err;
+
+	cm_dentry = debugfs_create_file("custom_method", S_IWUGO,
+					acpi_dir, NULL, &cm_fops);
+	if (!cm_dentry)
+		goto err;
+
+	return 0;
+
+err:
+	if (acpi_dir)
+		debugfs_remove(acpi_dir);
+	return -EINVAL;
+}
+
+/* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 #ifdef CONFIG_ACPI_PROCFS
@@ -286,7 +360,7 @@  static const struct file_operations acpi
 };
 #endif
 
-int __init acpi_debug_init(void)
+int __init acpi_procfs_init(void)
 {
 #ifdef CONFIG_ACPI_PROCFS
 	struct proc_dir_entry *entry;
@@ -321,3 +395,11 @@  int __init acpi_debug_init(void)
 	return 0;
 #endif
 }
+
+int __init acpi_debug_init(void)
+{
+	acpi_debugfs_init();
+	acpi_procfs_init();
+	return 0;
+}
+
Index: linux-2.6/Documentation/acpi/method_override.txt
===================================================================
--- /dev/null
+++ linux-2.6/Documentation/acpi/method_override.txt
@@ -0,0 +1,59 @@ 
+Linux ACPI Custom Control Method How To
+=======================================
+
+Written by Zhang Rui <rui.zhang@intel.com>
+
+
+Now Linux supports overriding an ACPI control method at runtime
+and users can use this instead of custom DSDT in most cases.
+
+This makes the AML code level debugging much easier,
+because kernel rebuild/reboot is not needed any more
+and the test results can be gotten in minutes.
+
+In order to make full use of this new debug method, here are the
+steps that should be followed by both users(bug reporters) and
+ACPI developers (ACPI bugzilla maintainers):
+
+1. users get the ACPI table AML code via /sys/firmware/acpi/tables,
+   and send them to ACPI developers
+2. ACPI developers disassemble the table and see if there are any
+   buggy methods
+3. ACPI developers edit the ASL code of the ACPI control method
+   that we want to override and save it in a new file
+4. ACPI developers package the new file to a SSDT table format
+5. ACPI developers assemble this file to generate the AML code of
+   the custom control method and send them to users
+6. users mount debugfs
+7. users test the custom ACPI control method via the debugfs
+8. users send the test results to ACPI developers.
+
+Here is an example about how I use it to override \_SB._AC._PSR,
+1. cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.dat
+2. cd /tmp
+3. iasl -d dsdt.dat
+4. copy the ASL code of \_SB._AC._PSR and paste it in a new file,
+   say psr.asl
+5. edit, save and package it to an ACPI table and here is the
+   output of "cat psr.asl"
+
+DefinitionBlock ("psr.aml", "SSDT", 1, "Sony", "VAIO", 0x20080715)
+{
+            Method (\_SB_.AC._PSR, 0, NotSerialized)
+            {
+                Store ("In AC _PSR", Debug)
+                Return (One)
+            }
+}
+
+6. iasl psr.asl (psr.aml is generated as a result of this step)
+7. mount -t debugfs none /sys/kernel/debug
+8. cat /tmp/psr.aml > /sys/kernel/debug/acpi/custom_method
+9. now the _PSR always returns 1, together with an ACPI Debug message.
+
+Note: Only ACPI METHOD can be overriden, any other object types like
+      "Device", "OperationRegion", are not recognized.
+Note: Only ONE ACPI method is overriden at a time. If an ACPI table
+      with multiple ACPI methods is sent to kernel, there are no
+      error message. Only the first method is actually overriden,
+      and any other methods in this table are ignored.