Re: [PATCH] ACPI: Enable SCI_EMULATE to manually simulate physicalhotplug testing.
From: Toshi Kani
Date: Tue Sep 04 2012 - 12:32:29 EST
On Mon, 2012-09-03 at 14:27 -0700, Yinghai Lu wrote:
> 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 /sys/kernel/debug/acpi/sci_notify when new kernel is
> booted.
>
> echo "\_SB.PCIB 1" > /sys/kernel/debug/acpi/sci_notify to trigger a hot-add
> of root bus that is corresponding to PCIB.
>
> echo "\_SB.PCIB 3" > /sys/kernel/debug/acpi/sci_notify to trigger a hot-remove
> of root bus that is corresponding to PCIB.
Hi Yinghai,
This feature has been very useful. Thanks for working on this change.
I have a few comments below.
> -v2: Update to current upstream, and remove not related stuff.
> -v3: According to Len's request, update it to use debugfs. - Yinghai Lu
>
> 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/sci_emu.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 156 insertions(+)
>
> Index: linux-2.6/drivers/acpi/Kconfig
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/Kconfig
> +++ linux-2.6/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 DEBUG_FS
> + 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" > /sys/kernel/debug/acpi/sci_notify (where, XXX is
> + a target ACPI device object name present under \_SB scope).
> +
> config ACPI_DEBUG
> bool "Debug Statements"
> default n
> Index: linux-2.6/drivers/acpi/sci_emu.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/acpi/sci_emu.c
> @@ -0,0 +1,145 @@
> +/*
> + * Code to emulate SCI interrupt for Hotplug node insertion/removal
> + */
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/uaccess.h>
> +#include <linux/debugfs.h>
> +#include <acpi/acpi_drivers.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");
> +MODULE_LICENSE("GPL");
> +
> +static struct dentry *sci_notify_dentry;
> +
> +static void 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);
Why do you obtain hsb for \_SB when acpi_name is supposed to be a full
path name? Can you simply specify a NULL like this?
status = acpi_get_handle(NULL, acpi_name, &hlsb);
> + if (ACPI_FAILURE(status) || ACPI_FAILURE(status1)) {
> + pr_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)) {
> + pr_err(PREFIX "Acquiring acpi namespace mutext failed\n");
> + return;
> + }
> +
> + node = acpi_ns_validate_handle(hlsb);
> + if (!node) {
> + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
> + pr_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.notify_list[0]) {
Is the above check necessary? acpi_ev_queue_notify_request() sets up to
call the global handler, acpi_gbl_global_notify[0], even if the object
does not have a local handler registered.
Thanks,
-Toshi
> + /*
> + * 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))
> + pr_err(PREFIX "acpi_ev_queue_notify_request failed\n");
> + else
> + pr_info(PREFIX "Notify event is queued\n");
> + return;
> + }
> + } else {
> + pr_info(PREFIX "Notify handler not registered for this device\n");
> + }
> +
> + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
> + return;
> +}
> +
> +static ssize_t sci_notify_write(struct file *file, const char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + u32 event;
> + char *name1 = NULL;
> + char *name2 = NULL;
> + const char *delim = " ";
> + char *temp_buf = NULL;
> + char *temp_buf_addr = NULL;
> +
> + temp_buf = kmalloc(count+1, GFP_ATOMIC);
> + if (!temp_buf) {
> + pr_warn(PREFIX "sci_notify_wire: Memory allocation failed\n");
> + return count;
> + }
> + temp_buf[count] = '\0';
> + temp_buf_addr = temp_buf;
> + if (copy_from_user(temp_buf, user_buf, count))
> + goto out;
> +
> + name1 = strsep(&temp_buf, delim);
> + name2 = strsep(&temp_buf, delim);
> +
> + if (name1 && name2) {
> + ssize_t ret;
> + unsigned long val;
> +
> + ret = kstrtoul(name2, 10, &val);
> + if (ret) {
> + pr_warn(PREFIX "unknown event\n");
> + goto out;
> + }
> +
> + event = (u32)val;
> + } else {
> + pr_warn(PREFIX "unknown device\n");
> + goto out;
> + }
> +
> + pr_info(PREFIX "ACPI device name is <%s>, event code is <%d>\n",
> + name1, event);
> +
> + sci_notify_client(name1, event);
> +
> +out:
> + kfree(temp_buf_addr);
> + return count;
> +}
> +
> +static const struct file_operations sci_notify_fops = {
> + .write = sci_notify_write,
> +};
> +
> +static int __init acpi_sci_notify_init(void)
> +{
> + if (acpi_debugfs_dir == NULL)
> + return -ENOENT;
> +
> + sci_notify_dentry = debugfs_create_file("sci_notify", S_IWUSR,
> + acpi_debugfs_dir, NULL, &sci_notify_fops);
> + if (sci_notify_dentry == NULL)
> + return -ENODEV;
> +
> + return 0;
> +}
> +
> +device_initcall(acpi_sci_notify_init);
> Index: linux-2.6/drivers/acpi/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/Makefile
> +++ linux-2.6/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
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/