Skip to contentSkip to conversation

genirq: support multiple interrupt priorities

RFC PATCH In review Paul Mundt 2 participants 3 messages Aug 6, 2007 IRQ

lore
Share & tools
lore

Paul Mundt

author
#0 lore raw

RFC PATCH 1/1 genirq: support multiple interrupt priorities

This is a simple patch for adding trivial interrupt priority support.

I've added a ->set_prio() to the irq_chip which is implemented effectively the same way as ->set_type(), it's an optional component for those that really care about it.

This follows the rationale that PICs that do support multiple priorities are going to support a fairly wide range, which is not something that can easily be represented generically. Given that, the only IRQF_PRIO_* flags that are introduced are for generic priorities that we assume all priority-capable PICs can support -- namely, high, low, and default (or none). In addition to this there is also a set_irq_prio() modelled after set_irq_type() which platform-specific code can set to more specific values that aren't suitable for generic abstraction.

My primary use case for this is for making sure we have high priorities where we want them in the platform code, especially chained handlers, timers, things of that nature. Going the genirq route is certainly much cleaner than trying to hack up my own arch-specific API for this. I imagine other people will have similar use cases for this.

Comments? Flames?

--

 include/linux/interrupt.h |    5 +++++
 include/linux/irq.h       |    3 +++
 kernel/irq/chip.c         |   26 ++++++++++++++++++++++++++
 kernel/irq/manage.c       |   16 ++++++++++++++++
 4 files changed, 50 insertions(+)
include/linux/interrupt.h +5 -0
index 5523f19..503754e 100644
@@ -45,6 +45,8 @@
  * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
  *                registered first in an shared interrupt is considered for
  *                performance reasons)
+ * IRQF_PRIO_HIGH - Give IRQ a high priority
+ * IRQF_PRIO_LOW - Give IRQ a low priority
  */
 #define IRQF_DISABLED		0x00000020
 #define IRQF_SAMPLE_RANDOM	0x00000040
@@ -54,6 +56,9 @@
 #define IRQF_PERCPU		0x00000400
 #define IRQF_NOBALANCING	0x00000800
 #define IRQF_IRQPOLL		0x00001000
+#define IRQF_PRIO_HIGH		0x00002000
+#define IRQF_PRIO_LOW		0x00004000
+#define IRQF_PRIO_MASK		(IRQF_PRIO_HIGH | IRQF_PRIO_LOW)
 
 /*
  * Migration helpers. Scheduled for removal in 9/2007
include/linux/irq.h +3 -0
index efc8853..88cfd33 100644
@@ -91,6 +96,7 @@ struct msi_desc;
  * @retrigger:		resend an IRQ to the CPU
  * @set_type:		set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
  * @set_wake:		enable/disable power-management wake-on of an IRQ
+ * @set_prio:		set the priority of an IRQ
  *
  * @release:		release function solely used by UML
  * @typename:		obsoleted by name, kept as migration helper
@@ -113,6 +119,7 @@ struct irq_chip {
 	int		(*retrigger)(unsigned int irq);
 	int		(*set_type)(unsigned int irq, unsigned int flow_type);
 	int		(*set_wake)(unsigned int irq, unsigned int on);
+	int		(*set_prio)(unsigned int irq, unsigned int prio);
 
 	/* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
@@ -381,6 +388,7 @@ extern int set_irq_data(unsigned int irq, void *data);
 extern int set_irq_chip_data(unsigned int irq, void *data);
 extern int set_irq_type(unsigned int irq, unsigned int type);
 extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
+extern int set_irq_prio(unsigned int irq, unsigned int prio);
 
 #define get_irq_chip(irq)	(irq_desc[irq].chip)
 #define get_irq_chip_data(irq)	(irq_desc[irq].chip_data)
kernel/irq/chip.c +26 -0
index 615ce97..fa7df4d 100644
@@ -141,6 +141,32 @@ int set_irq_type(unsigned int irq, unsigned int type)
 EXPORT_SYMBOL(set_irq_type);
 
 /**
+ *	set_irq_prio - set the irq priority for an irq
+ *	@irq:	irq number
+ *	@prio:	interrupt priority - see include/linux/interrupt.h
+ */
+int set_irq_prio(unsigned int irq, unsigned int prio)
+{
+	struct irq_desc *desc;
+	unsigned long flags;
+	int ret = -ENXIO;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to set irq priority for IRQ%d\n", irq);
+		return -ENODEV;
+	}
+
+	desc = irq_desc + irq;
+	if (desc->chip->set_prio) {
+		spin_lock_irqsave(&desc->lock, flags);
+		ret = desc->chip->set_prio(irq, prio);
+		spin_unlock_irqrestore(&desc->lock, flags);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(set_irq_prio);
+
+/**
  *	set_irq_data - set irq type data for an irq
  *	@irq:	Interrupt number
  *	@data:	Pointer to interrupt specific data
kernel/irq/manage.c +16 -0
index 203a518..f51f8d2 100644
@@ -347,6 +353,22 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 		} else
 			compat_irq_chip_set_default_handler(desc);
 
+		/* Setup the priority if configured: */
+		if (new->flags & IRQF_PRIO_MASK) {
+			if (desc->chip && desc->chip->set_prio)
+				desc->chip->set_prio(irq,
+						new->flags & IRQF_PRIO_MASK);
+			else
+				/*
+				 * IRQF_PRIO_* but the PIC does not support
+				 * multiple priorities?
+				 */
+				printk(KERN_WARNING "No IRQF_PRIO set_prio "
+				       "function for IRQ %d (%s)\n", irq,
+				       desc->chip ? desc->chip->name :
+				       "unknown");
+		}
+
 		desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
 				  IRQ_INPROGRESS);
 
#1 lore raw
Quoted 5 lines · Paul Mundt

This is a simple patch for adding trivial interrupt priority support.

I've added a ->set_prio() to the irq_chip which is implemented effectively the same way as ->set_type(), it's an optional component for those that really care about it.

i have no fundamental objections but it would be nice to actually prototype this by implementing real priority support in the hardware:
both the i8259A and the IO-APIC/local-apic has such IRQ prioritization features.

Quoted 2 lines

+ * IRQF_PRIO_HIGH - Give IRQ a high priority
+ * IRQF_PRIO_LOW - Give IRQ a low priority

this should be a numeric scale. (Preferably in the 1-99 range (the hardware can then do a lower-resolution thing out of it), so that we can directly map this to IRQ threads and SCHED_FIFO priorities in -rt.)

Ingo

author
#2 lore raw
Quoted 12 lines · Ingo Molnar
Quoted 5 lines · Paul Mundt

This is a simple patch for adding trivial interrupt priority support.

I've added a ->set_prio() to the irq_chip which is implemented effectively the same way as ->set_type(), it's an optional component for those that really care about it.

i have no fundamental objections but it would be nice to actually prototype this by implementing real priority support in the hardware:
both the i8259A and the IO-APIC/local-apic has such IRQ prioritization features.

I would not have written the patch if I did not have hardware that supported it. I suppose I can start with interfacing the x86 PICs if that makes it easier to swallow, though ;-)

Quoted 7 lines
Quoted 2 lines

+ * IRQF_PRIO_HIGH - Give IRQ a high priority
+ * IRQF_PRIO_LOW - Give IRQ a low priority

this should be a numeric scale. (Preferably in the 1-99 range (the hardware can then do a lower-resolution thing out of it), so that we can directly map this to IRQ threads and SCHED_FIFO priorities in -rt.)

I don't disagree with that, but that makes it a little hard to pass in a priority at request_irq() time. These IRQF_PRIO_HIGH/LOW are only for such usage, the intent is to have a numeric value that's more meaningful to the underlying hardware passed on to set_irq_prio() otherwise.

In any event, there's no problem with doing that anyways, both IRQF_PRIO_HIGH and IRQF_PRIO_LOW are substantially above the 1-99 range that the mask can be tested for if the underlying controller isn't interested in mapping the 1-99 range to its own view of priorities. Presumably you want this numeric range also reflected in the irq_desc for -rt? If so, I'll start hacking something up.