From b85ec923dc0086ce229e5ec3ed20b054570bfc8a Mon Sep 17 00:00:00 2001 From: Xiongfeng Wang Date: Tue, 18 Jun 2019 20:35:02 +0800 Subject: [PATCH] SCI interrupt emulation This patch can be used to send event to a namespace node. It is based on the following patchset. https://lwn.net/Articles/84089/ --- drivers/acpi/Kconfig | 11 ++++ drivers/acpi/bus.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fb91fe3..f93fa91 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -550,6 +550,16 @@ config ACPI_CONFIGFS if ARM64 source "drivers/acpi/arm64/Kconfig" +config ACPI_SCI_EMULATE + bool "ACPI SCI Event Emulation Support" + depends on ACPI + default n + help + This driver 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). + config ACPI_PPTT bool endif @@ -587,3 +597,4 @@ config X86_PM_TIMER You should nearly always say Y here because many modern systems require this timer. + diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d2e29a1..9733031 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -44,6 +44,19 @@ #include "internal.h" +#ifdef CONFIG_ACPI_SCI_EMULATE +#include +#include "acpica/accommon.h" +#include "acpica/acnamesp.h" +#include "acpica/acevents.h" +#include "acpica/acinterp.h" + +static int acpi_init_sci_emulate(void); +static void acpi_sci_notify_client(char *acpi_name, u32 event); +#else +#define acpi_init_sci_emulate() +#endif + #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("bus"); @@ -51,6 +64,10 @@ struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); +#ifdef CONFIG_ACPI_SCI_EMULATE +struct proc_dir_entry *acpi_sci_dir; +#endif + #ifdef CONFIG_X86 #ifdef CONFIG_ACPI_CUSTOM_DSDT static inline int set_copy_dsdt(const struct dmi_system_id *id) @@ -1221,6 +1238,8 @@ static int __init acpi_bus_init(void) */ acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); + acpi_init_sci_emulate(); + result = bus_register(&acpi_bus_type); if (!result) return 0; @@ -1269,3 +1288,136 @@ static int __init acpi_init(void) } subsys_initcall(acpi_init); + +#ifdef CONFIG_ACPI_SCI_EMULATE +/****** Code to emulate SCI interrupt for Hotplug node insertion/removal ******/ + +static ssize_t acpi_sci_notify_write_proc(struct file *file, const char __user *buffer, + size_t count, loff_t *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; + + printk(KERN_INFO PREFIX "Inside acpi_sci_notify_write_proc\n"); + + temp_buf = kmalloc(count+1, GFP_ATOMIC); + if (!temp_buf) { + printk(KERN_WARNING PREFIX "Inside 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; + unsigned long long sta; + //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) { + (void) 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 */ + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (event == 1) + acpi_evaluate_integer(hlsb, "_SCP", NULL, &sta); + 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"); +// } + + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return; +} + +int proc_sci_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%s\n", "test"); + + return 0; +} + +static int proc_sci_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, proc_sci_show, NULL); +} +struct file_operations notify_ops = { + .open = proc_sci_open, + .read = seq_read, + .llseek = seq_lseek, + .write = acpi_sci_notify_write_proc, + .release = single_release, +}; + +static int acpi_init_sci_emulate(void) +{ + ACPI_FUNCTION_TRACE("acpi_init_sci_emulate"); + + acpi_sci_dir = proc_mkdir("sci", acpi_root_dir); + if (!acpi_sci_dir) + return_VALUE(-ENODEV); + + proc_create("notify", S_IWUGO|S_IRUGO, acpi_sci_dir, ¬ify_ops); + + return_VALUE(0); +} +#endif -- 2.7.4