|
@@ -109,7 +109,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
|
|
/*
|
|
|
* Generic version of the affinity autoselector.
|
|
|
*/
|
|
|
-int do_irq_select_affinity(unsigned int irq, struct irq_desc *desc)
|
|
|
+static int setup_affinity(unsigned int irq, struct irq_desc *desc)
|
|
|
{
|
|
|
if (!irq_can_set_affinity(irq))
|
|
|
return 0;
|
|
@@ -133,7 +133,7 @@ set_affinity:
|
|
|
return 0;
|
|
|
}
|
|
|
#else
|
|
|
-static inline int do_irq_select_affinity(unsigned int irq, struct irq_desc *d)
|
|
|
+static inline int setup_affinity(unsigned int irq, struct irq_desc *d)
|
|
|
{
|
|
|
return irq_select_affinity(irq);
|
|
|
}
|
|
@@ -149,14 +149,14 @@ int irq_select_affinity_usr(unsigned int irq)
|
|
|
int ret;
|
|
|
|
|
|
spin_lock_irqsave(&desc->lock, flags);
|
|
|
- ret = do_irq_select_affinity(irq, desc);
|
|
|
+ ret = setup_affinity(irq, desc);
|
|
|
spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
#else
|
|
|
-static inline int do_irq_select_affinity(int irq, struct irq_desc *desc)
|
|
|
+static inline int setup_affinity(unsigned int irq, struct irq_desc *desc)
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
@@ -389,9 +389,9 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
|
|
|
* allocate special interrupts that are part of the architecture.
|
|
|
*/
|
|
|
static int
|
|
|
-__setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
|
|
|
+__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
|
|
|
{
|
|
|
- struct irqaction *old, **p;
|
|
|
+ struct irqaction *old, **old_ptr;
|
|
|
const char *old_name = NULL;
|
|
|
unsigned long flags;
|
|
|
int shared = 0;
|
|
@@ -423,8 +423,8 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
|
|
|
* The following block of code has to be executed atomically
|
|
|
*/
|
|
|
spin_lock_irqsave(&desc->lock, flags);
|
|
|
- p = &desc->action;
|
|
|
- old = *p;
|
|
|
+ old_ptr = &desc->action;
|
|
|
+ old = *old_ptr;
|
|
|
if (old) {
|
|
|
/*
|
|
|
* Can't share interrupts unless both agree to and are
|
|
@@ -447,8 +447,8 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
|
|
|
|
|
|
/* add new interrupt at end of irq queue */
|
|
|
do {
|
|
|
- p = &old->next;
|
|
|
- old = *p;
|
|
|
+ old_ptr = &old->next;
|
|
|
+ old = *old_ptr;
|
|
|
} while (old);
|
|
|
shared = 1;
|
|
|
}
|
|
@@ -488,7 +488,7 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
|
|
|
desc->status |= IRQ_NO_BALANCING;
|
|
|
|
|
|
/* Set default affinity mask once everything is setup */
|
|
|
- do_irq_select_affinity(irq, desc);
|
|
|
+ setup_affinity(irq, desc);
|
|
|
|
|
|
} else if ((new->flags & IRQF_TRIGGER_MASK)
|
|
|
&& (new->flags & IRQF_TRIGGER_MASK)
|
|
@@ -499,7 +499,7 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
|
|
|
(int)(new->flags & IRQF_TRIGGER_MASK));
|
|
|
}
|
|
|
|
|
|
- *p = new;
|
|
|
+ *old_ptr = new;
|
|
|
|
|
|
/* Reset broken irq detection when installing new handler */
|
|
|
desc->irq_count = 0;
|
|
@@ -549,90 +549,117 @@ int setup_irq(unsigned int irq, struct irqaction *act)
|
|
|
|
|
|
return __setup_irq(irq, desc, act);
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(setup_irq);
|
|
|
|
|
|
-/**
|
|
|
- * free_irq - free an interrupt
|
|
|
- * @irq: Interrupt line to free
|
|
|
- * @dev_id: Device identity to free
|
|
|
- *
|
|
|
- * Remove an interrupt handler. The handler is removed and if the
|
|
|
- * interrupt line is no longer in use by any driver it is disabled.
|
|
|
- * On a shared IRQ the caller must ensure the interrupt is disabled
|
|
|
- * on the card it drives before calling this function. The function
|
|
|
- * does not return until any executing interrupts for this IRQ
|
|
|
- * have completed.
|
|
|
- *
|
|
|
- * This function must not be called from interrupt context.
|
|
|
+ /*
|
|
|
+ * Internal function to unregister an irqaction - used to free
|
|
|
+ * regular and special interrupts that are part of the architecture.
|
|
|
*/
|
|
|
-void free_irq(unsigned int irq, void *dev_id)
|
|
|
+static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
- struct irqaction **p;
|
|
|
+ struct irqaction *action, **action_ptr;
|
|
|
unsigned long flags;
|
|
|
|
|
|
- WARN_ON(in_interrupt());
|
|
|
+ WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
|
|
|
|
|
|
if (!desc)
|
|
|
- return;
|
|
|
+ return NULL;
|
|
|
|
|
|
spin_lock_irqsave(&desc->lock, flags);
|
|
|
- p = &desc->action;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * There can be multiple actions per IRQ descriptor, find the right
|
|
|
+ * one based on the dev_id:
|
|
|
+ */
|
|
|
+ action_ptr = &desc->action;
|
|
|
for (;;) {
|
|
|
- struct irqaction *action = *p;
|
|
|
+ action = *action_ptr;
|
|
|
|
|
|
- if (action) {
|
|
|
- struct irqaction **pp = p;
|
|
|
+ if (!action) {
|
|
|
+ WARN(1, "Trying to free already-free IRQ %d\n", irq);
|
|
|
+ spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
|
|
|
- p = &action->next;
|
|
|
- if (action->dev_id != dev_id)
|
|
|
- continue;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- /* Found it - now remove it from the list of entries */
|
|
|
- *pp = action->next;
|
|
|
+ if (action->dev_id == dev_id)
|
|
|
+ break;
|
|
|
+ action_ptr = &action->next;
|
|
|
+ }
|
|
|
|
|
|
- /* Currently used only by UML, might disappear one day.*/
|
|
|
+ /* Found it - now remove it from the list of entries: */
|
|
|
+ *action_ptr = action->next;
|
|
|
+
|
|
|
+ /* Currently used only by UML, might disappear one day: */
|
|
|
#ifdef CONFIG_IRQ_RELEASE_METHOD
|
|
|
- if (desc->chip->release)
|
|
|
- desc->chip->release(irq, dev_id);
|
|
|
+ if (desc->chip->release)
|
|
|
+ desc->chip->release(irq, dev_id);
|
|
|
#endif
|
|
|
|
|
|
- if (!desc->action) {
|
|
|
- desc->status |= IRQ_DISABLED;
|
|
|
- if (desc->chip->shutdown)
|
|
|
- desc->chip->shutdown(irq);
|
|
|
- else
|
|
|
- desc->chip->disable(irq);
|
|
|
- }
|
|
|
- spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
- unregister_handler_proc(irq, action);
|
|
|
+ /* If this was the last handler, shut down the IRQ line: */
|
|
|
+ if (!desc->action) {
|
|
|
+ desc->status |= IRQ_DISABLED;
|
|
|
+ if (desc->chip->shutdown)
|
|
|
+ desc->chip->shutdown(irq);
|
|
|
+ else
|
|
|
+ desc->chip->disable(irq);
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
+
|
|
|
+ unregister_handler_proc(irq, action);
|
|
|
+
|
|
|
+ /* Make sure it's not being used on another CPU: */
|
|
|
+ synchronize_irq(irq);
|
|
|
|
|
|
- /* Make sure it's not being used on another CPU */
|
|
|
- synchronize_irq(irq);
|
|
|
-#ifdef CONFIG_DEBUG_SHIRQ
|
|
|
- /*
|
|
|
- * It's a shared IRQ -- the driver ought to be
|
|
|
- * prepared for it to happen even now it's
|
|
|
- * being freed, so let's make sure.... We do
|
|
|
- * this after actually deregistering it, to
|
|
|
- * make sure that a 'real' IRQ doesn't run in
|
|
|
- * parallel with our fake
|
|
|
- */
|
|
|
- if (action->flags & IRQF_SHARED) {
|
|
|
- local_irq_save(flags);
|
|
|
- action->handler(irq, dev_id);
|
|
|
- local_irq_restore(flags);
|
|
|
- }
|
|
|
-#endif
|
|
|
- kfree(action);
|
|
|
- return;
|
|
|
- }
|
|
|
- printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
|
|
|
#ifdef CONFIG_DEBUG_SHIRQ
|
|
|
- dump_stack();
|
|
|
-#endif
|
|
|
- spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
- return;
|
|
|
+ /*
|
|
|
+ * It's a shared IRQ -- the driver ought to be prepared for an IRQ
|
|
|
+ * event to happen even now it's being freed, so let's make sure that
|
|
|
+ * is so by doing an extra call to the handler ....
|
|
|
+ *
|
|
|
+ * ( We do this after actually deregistering it, to make sure that a
|
|
|
+ * 'real' IRQ doesn't run in * parallel with our fake. )
|
|
|
+ */
|
|
|
+ if (action->flags & IRQF_SHARED) {
|
|
|
+ local_irq_save(flags);
|
|
|
+ action->handler(irq, dev_id);
|
|
|
+ local_irq_restore(flags);
|
|
|
}
|
|
|
+#endif
|
|
|
+ return action;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * remove_irq - free an interrupt
|
|
|
+ * @irq: Interrupt line to free
|
|
|
+ * @act: irqaction for the interrupt
|
|
|
+ *
|
|
|
+ * Used to remove interrupts statically setup by the early boot process.
|
|
|
+ */
|
|
|
+void remove_irq(unsigned int irq, struct irqaction *act)
|
|
|
+{
|
|
|
+ __free_irq(irq, act->dev_id);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(remove_irq);
|
|
|
+
|
|
|
+/**
|
|
|
+ * free_irq - free an interrupt allocated with request_irq
|
|
|
+ * @irq: Interrupt line to free
|
|
|
+ * @dev_id: Device identity to free
|
|
|
+ *
|
|
|
+ * Remove an interrupt handler. The handler is removed and if the
|
|
|
+ * interrupt line is no longer in use by any driver it is disabled.
|
|
|
+ * On a shared IRQ the caller must ensure the interrupt is disabled
|
|
|
+ * on the card it drives before calling this function. The function
|
|
|
+ * does not return until any executing interrupts for this IRQ
|
|
|
+ * have completed.
|
|
|
+ *
|
|
|
+ * This function must not be called from interrupt context.
|
|
|
+ */
|
|
|
+void free_irq(unsigned int irq, void *dev_id)
|
|
|
+{
|
|
|
+ kfree(__free_irq(irq, dev_id));
|
|
|
}
|
|
|
EXPORT_SYMBOL(free_irq);
|
|
|
|
|
@@ -679,11 +706,12 @@ int request_irq(unsigned int irq, irq_handler_t handler,
|
|
|
* the behavior is classified as "will not fix" so we need to
|
|
|
* start nudging drivers away from using that idiom.
|
|
|
*/
|
|
|
- if ((irqflags & (IRQF_SHARED|IRQF_DISABLED))
|
|
|
- == (IRQF_SHARED|IRQF_DISABLED))
|
|
|
- pr_warning("IRQ %d/%s: IRQF_DISABLED is not "
|
|
|
- "guaranteed on shared IRQs\n",
|
|
|
- irq, devname);
|
|
|
+ if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==
|
|
|
+ (IRQF_SHARED|IRQF_DISABLED)) {
|
|
|
+ pr_warning(
|
|
|
+ "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
|
|
|
+ irq, devname);
|
|
|
+ }
|
|
|
|
|
|
#ifdef CONFIG_LOCKDEP
|
|
|
/*
|
|
@@ -709,15 +737,13 @@ int request_irq(unsigned int irq, irq_handler_t handler,
|
|
|
if (!handler)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
|
|
|
+ action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
|
|
|
if (!action)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
action->handler = handler;
|
|
|
action->flags = irqflags;
|
|
|
- cpus_clear(action->mask);
|
|
|
action->name = devname;
|
|
|
- action->next = NULL;
|
|
|
action->dev_id = dev_id;
|
|
|
|
|
|
retval = __setup_irq(irq, desc, action);
|