[5/7] Xen VMM #3: split free_irq into teardown_irq

From: Ian Pratt
Date: Mon Nov 29 2004 - 21:24:42 EST



This patch moves the `unregister the irqaction' part of free_irq into
a new function teardown_irq, leaving only the mapping from dev_id to
irqaction and freeing the irqaction in free_irq. free_irq
calls teardown_irq to unregister the irqaction. This is similar
to how setup_irq and request_irq work for registering irq's.
We need teardown_irq to allow us to unregister irq's which were
registered early during boot when memory management wasn't ready
yet, i.e. irq's which were registered using setup_irq and use a static
irqaction which cannot be kfree'd.

Signed-off-by: ian.pratt@xxxxxxxxxxxx

---
diff -Nurp pristine-linux-2.6.10-rc2/include/linux/irq.h tmp-linux-2.6.10-rc2-xen.patch/include/linux/irq.h
--- pristine-linux-2.6.10-rc2/include/linux/irq.h 2004-11-30 01:20:24.000000000 +0000
+++ tmp-linux-2.6.10-rc2-xen.patch/include/linux/irq.h 2004-11-30 00:41:24.000000000 +0000
@@ -73,6 +73,7 @@ extern irq_desc_t irq_desc [NR_IRQS];
#include <asm/hw_irq.h> /* the arch dependent stuff */

extern int setup_irq(unsigned int irq, struct irqaction * new);
+extern int teardown_irq(unsigned int irq, struct irqaction * old);

#ifdef CONFIG_GENERIC_HARDIRQS
extern cpumask_t irq_affinity[NR_IRQS];
diff -Nurp pristine-linux-2.6.10-rc2/kernel/irq/manage.c tmp-linux-2.6.10-rc2-xen.patch/kernel/irq/manage.c
--- pristine-linux-2.6.10-rc2/kernel/irq/manage.c 2004-11-30 01:20:25.000000000 +0000
+++ tmp-linux-2.6.10-rc2-xen.patch/kernel/irq/manage.c 2004-11-30 00:54:43.000000000 +0000
@@ -144,9 +144,14 @@ int can_request_irq(unsigned int irq, un
return !action;
}

-/*
- * Internal function to register an irqaction - typically used to
- * allocate special interrupts that are part of the architecture.
+/**
+ * setup_irq - register an irqaction structure
+ * @irq: Interrupt to register
+ * @irqaction: The irqaction structure to be registered
+ *
+ * Normally called by request_irq, this function can be used
+ * directly to allocate special interrupts that are part of the
+ * architecture.
*/
int setup_irq(unsigned int irq, struct irqaction * new)
{
@@ -215,28 +220,27 @@ int setup_irq(unsigned int irq, struct i
return 0;
}

-/**
- * 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.
+/*
+ * teardown_irq - unregister an irqaction
+ * @irq: Interrupt line being freed
+ * @old: Pointer to the irqaction that is to be unregistered
+ *
+ * This function is called by free_irq and does the actual
+ * business of unregistering the handler. It exists as a
+ * seperate function to enable handlers to be unregistered
+ * for irqactions that have been allocated statically at
+ * boot time.
*
* This function must not be called from interrupt context.
*/
-void free_irq(unsigned int irq, void *dev_id)
+int teardown_irq(unsigned int irq, struct irqaction * old)
{
struct irq_desc *desc;
struct irqaction **p;
unsigned long flags;

if (irq >= NR_IRQS)
- return;
+ return -ENOENT;

desc = irq_desc + irq;
spin_lock_irqsave(&desc->lock,flags);
@@ -248,7 +252,7 @@ void free_irq(unsigned int irq, void *de
struct irqaction **pp = p;

p = &action->next;
- if (action->dev_id != dev_id)
+ if (action != old)
continue;

/* Found it - now remove it from the list of entries */
@@ -265,13 +269,52 @@ void free_irq(unsigned int irq, void *de

/* Make sure it's not being used on another CPU */
synchronize_irq(irq);
- kfree(action);
- return;
+ return 0;
}
- printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+ printk(KERN_ERR "Trying to teardown free IRQ%d\n",irq);
spin_unlock_irqrestore(&desc->lock,flags);
+ return -ENOENT;
+ }
+}
+
+/**
+ * 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.
+ */
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irq_desc *desc;
+ struct irqaction *action;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS)
+ return;
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ for (action = desc->action; action != NULL; action = action->next) {
+ if (action->dev_id != dev_id)
+ continue;
+
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ if (teardown_irq(irq, action) == 0)
+ kfree(action);
return;
}
+ printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
}

EXPORT_SYMBOL(free_irq);
-
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/