]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 9 Jul 2017 17:24:46 +0000 (10:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 9 Jul 2017 17:24:46 +0000 (10:24 -0700)
Pull irq fixes from Thomas Gleixner:

 - A few fixes mopping up the fallout of the big irq overhaul

 - Move the interrupt resource management logic out of the spin locked,
   irq disabled region to avoid unnecessary restrictions of the resource
   callbacks

 - Preparation for reworking the per cpu irq request function.

* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  irqdomain: Allow ACPI device nodes to be used as irqdomain identifiers
  genirq/debugfs: Remove redundant NULL pointer check
  genirq: Allow to pass the IRQF_TIMER flag with percpu irq request
  genirq/timings: Move free timings out of spinlocked region
  genirq: Move irq resource handling out of spinlocked region
  genirq: Add mutex to irq desc to serialize request/free_irq()
  genirq: Move bus locking into __setup_irq()
  genirq: Force inlining of __irq_startup_managed to prevent build failure
  genirq/debugfs: Fix build for !CONFIG_IRQ_DOMAIN

include/linux/interrupt.h
include/linux/irqdesc.h
kernel/irq/chip.c
kernel/irq/internals.h
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c

index 431e1d83e27458efe83ccbad914d7cc191e8162a..a2fddddb0d601ec1e7cc2633643284cfebc7ef9c 100644 (file)
@@ -152,8 +152,17 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,
                        unsigned long flags, const char *name, void *dev_id);
 
 extern int __must_check
+__request_percpu_irq(unsigned int irq, irq_handler_t handler,
+                    unsigned long flags, const char *devname,
+                    void __percpu *percpu_dev_id);
+
+static inline int __must_check
 request_percpu_irq(unsigned int irq, irq_handler_t handler,
-                  const char *devname, void __percpu *percpu_dev_id);
+                  const char *devname, void __percpu *percpu_dev_id)
+{
+       return __request_percpu_irq(irq, handler, 0,
+                                   devname, percpu_dev_id);
+}
 
 extern const void *free_irq(unsigned int, void *);
 extern void free_percpu_irq(unsigned int, void __percpu *);
index d425a3a097227ed7e3e83c6fbfb8219cab55d9ed..3e90a094798d2955054db8f8bee381cb07dcfde9 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/rcupdate.h>
 #include <linux/kobject.h>
+#include <linux/mutex.h>
 
 /*
  * Core internal functions to deal with irq descriptors
@@ -45,6 +46,7 @@ struct pt_regs;
  *                     IRQF_FORCE_RESUME set
  * @rcu:               rcu head for delayed free
  * @kobj:              kobject used to represent this struct in sysfs
+ * @request_mutex:     mutex to protect request/free before locking desc->lock
  * @dir:               /proc/irq/ procfs entry
  * @debugfs_file:      dentry for the debugfs file
  * @name:              flow handler name for /proc/interrupts output
@@ -96,6 +98,7 @@ struct irq_desc {
        struct rcu_head         rcu;
        struct kobject          kobj;
 #endif
+       struct mutex            request_mutex;
        int                     parent_irq;
        struct module           *owner;
        const char              *name;
index ad43468e89f0e9038db8d04b0e5097ba192c9080..d171bc57e1e01830d6540cdcef145d25797f1393 100644 (file)
@@ -234,7 +234,7 @@ __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
        return IRQ_STARTUP_MANAGED;
 }
 #else
-static int
+static __always_inline int
 __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
 {
        return IRQ_STARTUP_NORMAL;
index 9da14d125df4d2ef5383aa83b99666dca9c86d89..dbfba9933ed251c23deb6eb9e34155b1ca1c19f2 100644 (file)
@@ -437,7 +437,9 @@ static inline void irq_remove_debugfs_entry(struct irq_desc *desc)
 # ifdef CONFIG_IRQ_DOMAIN
 void irq_domain_debugfs_init(struct dentry *root);
 # else
-static inline void irq_domain_debugfs_init(struct dentry *root);
+static inline void irq_domain_debugfs_init(struct dentry *root)
+{
+}
 # endif
 #else /* CONFIG_GENERIC_IRQ_DEBUGFS */
 static inline void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *d)
index 8bbd06405e608719c9ce108a7e49b75b055b7b9e..73be2b3909bd40a373e9c5237575faed5812945f 100644 (file)
@@ -373,6 +373,7 @@ static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags,
 
        raw_spin_lock_init(&desc->lock);
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+       mutex_init(&desc->request_mutex);
        init_rcu_head(&desc->rcu);
 
        desc_set_defaults(irq, desc, node, affinity, owner);
index 14fe862aa2e36a26d8b97ee5b411bbca87921016..f1f251479aa6009eddb81041f69e825ebb8d28b7 100644 (file)
@@ -1,5 +1,6 @@
 #define pr_fmt(fmt)  "irq: " fmt
 
+#include <linux/acpi.h>
 #include <linux/debugfs.h>
 #include <linux/hardirq.h>
 #include <linux/interrupt.h>
@@ -155,6 +156,21 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
                        domain->name = fwid->name;
                        break;
                }
+#ifdef CONFIG_ACPI
+       } else if (is_acpi_device_node(fwnode)) {
+               struct acpi_buffer buf = {
+                       .length = ACPI_ALLOCATE_BUFFER,
+               };
+               acpi_handle handle;
+
+               handle = acpi_device_handle(to_acpi_device_node(fwnode));
+               if (acpi_get_name(handle, ACPI_FULL_PATHNAME, &buf) == AE_OK) {
+                       domain->name = buf.pointer;
+                       domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
+               }
+
+               domain->fwnode = fwnode;
+#endif
        } else if (of_node) {
                char *name;
 
@@ -1667,8 +1683,7 @@ static void debugfs_add_domain_dir(struct irq_domain *d)
 
 static void debugfs_remove_domain_dir(struct irq_domain *d)
 {
-       if (d->debugfs_file)
-               debugfs_remove(d->debugfs_file);
+       debugfs_remove(d->debugfs_file);
 }
 
 void __init irq_domain_debugfs_init(struct dentry *root)
index 5c11c1730ba5ee66f59d47c5ed1e59ff273df139..5624b2dd6b5807a0658dd8ce1a9bb3dd62a75209 100644 (file)
@@ -1167,6 +1167,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
                new->flags &= ~IRQF_ONESHOT;
 
+       mutex_lock(&desc->request_mutex);
+       if (!desc->action) {
+               ret = irq_request_resources(desc);
+               if (ret) {
+                       pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
+                              new->name, irq, desc->irq_data.chip->name);
+                       goto out_mutex;
+               }
+       }
+
+       chip_bus_lock(desc);
+
        /*
         * The following block of code has to be executed atomically
         */
@@ -1267,13 +1279,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        }
 
        if (!shared) {
-               ret = irq_request_resources(desc);
-               if (ret) {
-                       pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
-                              new->name, irq, desc->irq_data.chip->name);
-                       goto out_unlock;
-               }
-
                init_waitqueue_head(&desc->wait_for_threads);
 
                /* Setup the type (level, edge polarity) if configured: */
@@ -1347,6 +1352,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        }
 
        raw_spin_unlock_irqrestore(&desc->lock, flags);
+       chip_bus_sync_unlock(desc);
+       mutex_unlock(&desc->request_mutex);
 
        irq_setup_timings(desc, new);
 
@@ -1378,6 +1385,14 @@ mismatch:
 out_unlock:
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 
+       chip_bus_sync_unlock(desc);
+
+       if (!desc->action)
+               irq_release_resources(desc);
+
+out_mutex:
+       mutex_unlock(&desc->request_mutex);
+
 out_thread:
        if (new->thread) {
                struct task_struct *t = new->thread;
@@ -1417,9 +1432,7 @@ int setup_irq(unsigned int irq, struct irqaction *act)
        if (retval < 0)
                return retval;
 
-       chip_bus_lock(desc);
        retval = __setup_irq(irq, desc, act);
-       chip_bus_sync_unlock(desc);
 
        if (retval)
                irq_chip_pm_put(&desc->irq_data);
@@ -1443,6 +1456,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
        if (!desc)
                return NULL;
 
+       mutex_lock(&desc->request_mutex);
        chip_bus_lock(desc);
        raw_spin_lock_irqsave(&desc->lock, flags);
 
@@ -1475,8 +1489,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
        if (!desc->action) {
                irq_settings_clr_disable_unlazy(desc);
                irq_shutdown(desc);
-               irq_release_resources(desc);
-               irq_remove_timings(desc);
        }
 
 #ifdef CONFIG_SMP
@@ -1518,6 +1530,13 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
                }
        }
 
+       if (!desc->action) {
+               irq_release_resources(desc);
+               irq_remove_timings(desc);
+       }
+
+       mutex_unlock(&desc->request_mutex);
+
        irq_chip_pm_put(&desc->irq_data);
        module_put(desc->owner);
        kfree(action->secondary);
@@ -1674,9 +1693,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
                return retval;
        }
 
-       chip_bus_lock(desc);
        retval = __setup_irq(irq, desc, action);
-       chip_bus_sync_unlock(desc);
 
        if (retval) {
                irq_chip_pm_put(&desc->irq_data);
@@ -1924,9 +1941,7 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)
        if (retval < 0)
                return retval;
 
-       chip_bus_lock(desc);
        retval = __setup_irq(irq, desc, act);
-       chip_bus_sync_unlock(desc);
 
        if (retval)
                irq_chip_pm_put(&desc->irq_data);
@@ -1935,9 +1950,10 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)
 }
 
 /**
- *     request_percpu_irq - allocate a percpu interrupt line
+ *     __request_percpu_irq - allocate a percpu interrupt line
  *     @irq: Interrupt line to allocate
  *     @handler: Function to be called when the IRQ occurs.
+ *     @flags: Interrupt type flags (IRQF_TIMER only)
  *     @devname: An ascii name for the claiming device
  *     @dev_id: A percpu cookie passed back to the handler function
  *
@@ -1950,8 +1966,9 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)
  *     the handler gets called with the interrupted CPU's instance of
  *     that variable.
  */
-int request_percpu_irq(unsigned int irq, irq_handler_t handler,
-                      const char *devname, void __percpu *dev_id)
+int __request_percpu_irq(unsigned int irq, irq_handler_t handler,
+                        unsigned long flags, const char *devname,
+                        void __percpu *dev_id)
 {
        struct irqaction *action;
        struct irq_desc *desc;
@@ -1965,12 +1982,15 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler,
            !irq_settings_is_per_cpu_devid(desc))
                return -EINVAL;
 
+       if (flags && flags != IRQF_TIMER)
+               return -EINVAL;
+
        action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
        if (!action)
                return -ENOMEM;
 
        action->handler = handler;
-       action->flags = IRQF_PERCPU | IRQF_NO_SUSPEND;
+       action->flags = flags | IRQF_PERCPU | IRQF_NO_SUSPEND;
        action->name = devname;
        action->percpu_dev_id = dev_id;
 
@@ -1980,9 +2000,7 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler,
                return retval;
        }
 
-       chip_bus_lock(desc);
        retval = __setup_irq(irq, desc, action);
-       chip_bus_sync_unlock(desc);
 
        if (retval) {
                irq_chip_pm_put(&desc->irq_data);
@@ -1991,7 +2009,7 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler,
 
        return retval;
 }
-EXPORT_SYMBOL_GPL(request_percpu_irq);
+EXPORT_SYMBOL_GPL(__request_percpu_irq);
 
 /**
  *     irq_get_irqchip_state - returns the irqchip state of a interrupt.