Merge tag 'renesas-sh-drivers-for-v4.5' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / acpi / osl.c
index 32d684a..67da6fb 100644 (file)
@@ -220,6 +220,7 @@ void acpi_os_printf(const char *fmt, ...)
        acpi_os_vprintf(fmt, args);
        va_end(args);
 }
+EXPORT_SYMBOL(acpi_os_printf);
 
 void acpi_os_vprintf(const char *fmt, va_list args)
 {
@@ -234,7 +235,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
                printk(KERN_CONT "%s", buffer);
        }
 #else
-       printk(KERN_CONT "%s", buffer);
+       if (acpi_debugger_write_log(buffer) < 0)
+               printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -364,6 +366,19 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
                iounmap(vaddr);
 }
 
+/**
+ * acpi_os_map_iomem - Get a virtual address for a given physical address range.
+ * @phys: Start of the physical address range to map.
+ * @size: Size of the physical address range to map.
+ *
+ * Look up the given physical address range in the list of existing ACPI memory
+ * mappings.  If found, get a reference to it and return a pointer to it (its
+ * virtual address).  If not found, map it, add it to that list and return a
+ * pointer to it.
+ *
+ * During early init (when acpi_gbl_permanent_mmap has not been set yet) this
+ * routine simply calls __acpi_map_table() to get the job done.
+ */
 void __iomem *__init_refok
 acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
 {
@@ -439,6 +454,20 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map)
        }
 }
 
+/**
+ * acpi_os_unmap_iomem - Drop a memory mapping reference.
+ * @virt: Start of the address range to drop a reference to.
+ * @size: Size of the address range to drop a reference to.
+ *
+ * Look up the given virtual address range in the list of existing ACPI memory
+ * mappings, drop a reference to it and unmap it if there are no more active
+ * references to it.
+ *
+ * During early init (when acpi_gbl_permanent_mmap has not been set yet) this
+ * routine simply calls __acpi_unmap_table() to get the job done.  Since
+ * __acpi_unmap_table() is an __init function, the __ref annotation is needed
+ * here.
+ */
 void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
 {
        struct acpi_ioremap *map;
@@ -1101,6 +1130,200 @@ static void acpi_os_execute_deferred(struct work_struct *work)
        kfree(dpc);
 }
 
+#ifdef CONFIG_ACPI_DEBUGGER
+static struct acpi_debugger acpi_debugger;
+static bool acpi_debugger_initialized;
+
+int acpi_register_debugger(struct module *owner,
+                          const struct acpi_debugger_ops *ops)
+{
+       int ret = 0;
+
+       mutex_lock(&acpi_debugger.lock);
+       if (acpi_debugger.ops) {
+               ret = -EBUSY;
+               goto err_lock;
+       }
+
+       acpi_debugger.owner = owner;
+       acpi_debugger.ops = ops;
+
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+EXPORT_SYMBOL(acpi_register_debugger);
+
+void acpi_unregister_debugger(const struct acpi_debugger_ops *ops)
+{
+       mutex_lock(&acpi_debugger.lock);
+       if (ops == acpi_debugger.ops) {
+               acpi_debugger.ops = NULL;
+               acpi_debugger.owner = NULL;
+       }
+       mutex_unlock(&acpi_debugger.lock);
+}
+EXPORT_SYMBOL(acpi_unregister_debugger);
+
+int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context)
+{
+       int ret;
+       int (*func)(acpi_osd_exec_callback, void *);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->create_thread;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(function, context);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+ssize_t acpi_debugger_write_log(const char *msg)
+{
+       ssize_t ret;
+       ssize_t (*func)(const char *);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->write_log;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(msg);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length)
+{
+       ssize_t ret;
+       ssize_t (*func)(char *, size_t);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->read_cmd;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(buffer, buffer_length);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+int acpi_debugger_wait_command_ready(void)
+{
+       int ret;
+       int (*func)(bool, char *, size_t);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->wait_command_ready;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(acpi_gbl_method_executing,
+                  acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+int acpi_debugger_notify_command_complete(void)
+{
+       int ret;
+       int (*func)(void);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->notify_command_complete;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func();
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+int __init acpi_debugger_init(void)
+{
+       mutex_init(&acpi_debugger.lock);
+       acpi_debugger_initialized = true;
+       return 0;
+}
+#endif
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_os_execute
@@ -1127,6 +1350,15 @@ acpi_status acpi_os_execute(acpi_execute_type type,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
                          function, context));
 
+       if (type == OSL_DEBUGGER_MAIN_THREAD) {
+               ret = acpi_debugger_create_thread(function, context);
+               if (ret) {
+                       pr_err("Call to kthread_create() failed.\n");
+                       status = AE_ERROR;
+               }
+               goto out_thread;
+       }
+
        /*
         * Allocate/initialize DPC structure.  Note that this memory will be
         * freed by the callee.  The kernel handles the work_struct list  in a
@@ -1151,11 +1383,17 @@ acpi_status acpi_os_execute(acpi_execute_type type,
        if (type == OSL_NOTIFY_HANDLER) {
                queue = kacpi_notify_wq;
                INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-       } else {
+       } else if (type == OSL_GPE_HANDLER) {
                queue = kacpid_wq;
                INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+       } else {
+               pr_err("Unsupported os_execute type %d.\n", type);
+               status = AE_ERROR;
        }
 
+       if (ACPI_FAILURE(status))
+               goto err_workqueue;
+
        /*
         * On some machines, a software-initiated SMI causes corruption unless
         * the SMI runs on CPU 0.  An SMI can be initiated by any AML, but
@@ -1164,13 +1402,15 @@ acpi_status acpi_os_execute(acpi_execute_type type,
         * queueing on CPU 0.
         */
        ret = queue_work_on(0, queue, &dpc->work);
-
        if (!ret) {
                printk(KERN_ERR PREFIX
                          "Call to queue_work() failed.\n");
                status = AE_ERROR;
-               kfree(dpc);
        }
+err_workqueue:
+       if (ACPI_FAILURE(status))
+               kfree(dpc);
+out_thread:
        return status;
 }
 EXPORT_SYMBOL(acpi_os_execute);
@@ -1358,10 +1598,39 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
                chars = strlen(buffer) - 1;
                buffer[chars] = '\0';
        }
+#else
+       int ret;
+
+       ret = acpi_debugger_read_cmd(buffer, buffer_length);
+       if (ret < 0)
+               return AE_ERROR;
+       if (bytes_read)
+               *bytes_read = ret;
 #endif
 
        return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
+
+acpi_status acpi_os_wait_command_ready(void)
+{
+       int ret;
+
+       ret = acpi_debugger_wait_command_ready();
+       if (ret < 0)
+               return AE_ERROR;
+       return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+       int ret;
+
+       ret = acpi_debugger_notify_command_complete();
+       if (ret < 0)
+               return AE_ERROR;
+       return AE_OK;
+}
 
 acpi_status acpi_os_signal(u32 function, void *info)
 {