From: Ashok Raj <ashok.raj@xxxxxxxxx> Emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful for testing ACPI based hot-plug on systems that don't have the necessary firmware support. Enable CONFIG_ACPI_SCI_EMULATE on kernel compile. Now you will notice /proc/acpi/sci/notify when new kernel is booted. echo "\_SB.CPU4 1" > /proc/acpi/sci/notify to trigger a hot-add of CPU4. You will now notice an entry /sys/firmware/acpi/namespace/ACPI/_SB/CPU4 if the namespace had an entry CPU4 under _SB scope. If the entry had a _EJ0 method, you will also notice a file "eject" under the CPU4 directory. -v2: Update to current upstream, and remove not related stuff. Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> Cc: Len Brown <lenb@xxxxxxxxxx> Cc: linux-acpi@xxxxxxxxxxxxxxx =================================================================== --- drivers/acpi/Kconfig | 10 +++ drivers/acpi/Makefile | 1 + drivers/acpi/bus.c | 2 + drivers/acpi/internal.h | 6 ++ drivers/acpi/sci_emu.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 160 insertions(+), 0 deletions(-) create mode 100644 drivers/acpi/sci_emu.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 7556913..b7b8541 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -272,6 +272,16 @@ config ACPI_BLACKLIST_YEAR Enter 0 to disable this mechanism and allow ACPI to run by default no matter what the year. (default) +config ACPI_SCI_EMULATE + bool "ACPI SCI Event Emulation Support" + depends on ACPI + default n + help + This will enable your system to emulate sci hotplug event + notification through proc file system. For example user needs to + echo "XXX 0" > /proc/acpi/sci/notify (where, XXX is a target ACPI + device object name present under \_SB scope). + config ACPI_DEBUG bool "Debug Statements" default n diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index bc6e53f..3580f04 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -31,6 +31,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o # ACPI Bus and Device Drivers # acpi-y += bus.o glue.o +acpi-$(CONFIG_ACPI_SCI_EMULATE) += sci_emu.o acpi-y += scan.o acpi-y += processor_core.o acpi-y += ec.o diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9ecec98..512235e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1001,6 +1001,8 @@ static int __init acpi_bus_init(void) */ acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); + acpi_init_sci_emulate(); + return 0; /* Mimic structured exception handling */ diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ca75b9c..5b22cd2 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -34,6 +34,12 @@ int acpi_debugfs_init(void); static inline void acpi_debugfs_init(void) { return; } #endif +#ifdef CONFIG_ACPI_SCI_EMULATE +int acpi_init_sci_emulate(void); +#else +static inline int acpi_init_sci_emulate(void) { return 0; } +#endif + /* -------------------------------------------------------------------------- Power Resource -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/sci_emu.c b/drivers/acpi/sci_emu.c new file mode 100644 index 0000000..d972436 --- /dev/null +++ b/drivers/acpi/sci_emu.c @@ -0,0 +1,141 @@ +/* + * Code to emulate SCI interrupt for Hotplug node insertion/removal + */ +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/acpi.h> + +#include "internal.h" + +#include "acpica/accommon.h" +#include "acpica/acnamesp.h" +#include "acpica/acevents.h" + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME("sci_emu"); + +static void acpi_sci_notify_client(char *acpi_name, u32 event); +static int acpi_sci_notify_write_proc(struct file *file, const char *buffer, \ + unsigned long count, void *data); +struct proc_dir_entry *acpi_sci_dir; + +static int acpi_sci_notify_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + u32 event; + char *name1 = NULL; + char *name2 = NULL; + char *end_name = NULL; + const char *delim = " "; + char *temp_buf = NULL; + char *temp_buf_addr = NULL; + + temp_buf = kmalloc(count+1, GFP_ATOMIC); + if (!temp_buf) { + printk(KERN_WARNING PREFIX + "acpi_sci_notify_wire_proc: Memory allocation failed\n"); + return count; + } + temp_buf[count] = '\0'; + temp_buf_addr = temp_buf; + memcpy(temp_buf, buffer, count); + name1 = strsep(&temp_buf, delim); + name2 = strsep(&temp_buf, delim); + + if (name1 && name2) + event = simple_strtoul(name2, &end_name, 10); + else { + printk(KERN_WARNING PREFIX "unknown device\n"); + kfree(temp_buf_addr); + return count; + } + + printk(KERN_INFO PREFIX + "ACPI device name is <%s>, event code is <%d>\n", + name1, event); + + acpi_sci_notify_client(name1, event); + + kfree(temp_buf_addr); + + return count; +} + +static void acpi_sci_notify_client(char *acpi_name, u32 event) +{ + struct acpi_namespace_node *node; + acpi_status status, status1; + acpi_handle hlsb, hsb; + union acpi_operand_object *obj_desc; + + status = acpi_get_handle(NULL, "\\_SB", &hsb); + status1 = acpi_get_handle(hsb, acpi_name, &hlsb); + if (ACPI_FAILURE(status) || ACPI_FAILURE(status1)) { + printk(KERN_ERR PREFIX + "acpi getting handle to <\\_SB.%s> failed inside notify_client\n", + acpi_name); + return; + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Acquiring acpi namespace mutext failed\n"); + return; + } + + node = acpi_ns_validate_handle(hlsb); + if (!node) { + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + printk(KERN_ERR PREFIX "Mapping handle to node failed\n"); + return; + } + + /* + * Check for internal object and make sure there is a handler + * registered for this object + */ + obj_desc = acpi_ns_get_attached_object(node); + if (obj_desc) { + if (obj_desc->common_notify.system_notify) { + /* + * Release the lock and queue the item for later + * exectuion + */ + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + status = acpi_ev_queue_notify_request(node, event); + if (ACPI_FAILURE(status)) + printk(KERN_ERR PREFIX "acpi_ev_queue_notify_request failed\n"); + else + printk(KERN_INFO PREFIX "Notify event is queued\n"); + return; + } + } else { + printk(KERN_INFO PREFIX "Notify handler not registered for this device\n"); + } + + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return; +} + +int __init acpi_init_sci_emulate(void) +{ + struct proc_dir_entry *notify_entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_init_sci_emulate"); + + acpi_sci_dir = proc_mkdir("sci", acpi_root_dir); + if (!acpi_sci_dir) + return_VALUE(-ENODEV); + + notify_entry = create_proc_entry("notify", \ + S_IWUGO|S_IRUGO, acpi_sci_dir); + if (!notify_entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INIT, + "Unable to create '%s' fs entry\n", "notify")); + } else { + notify_entry->write_proc = acpi_sci_notify_write_proc; + notify_entry->data = NULL; + } + + return_VALUE(0); +} -- 1.7.7 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html