From 690803acca14e8aa101ca5204f0a23c24d7ad8c3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:18 +0100 Subject: irqchip: i8259: Add domain before mapping parent irq Mapping the parent IRQ will use a virq number which may conflict with the hardcoded I8259A_IRQ_BASE..I8259A_IRQ_BASE+15 range that the i8259 driver expects to be free. If this occurs then we'll hit errors when adding the i8259 IRQ domain, since one of its virq numbers will already be in use. Avoid this by adding the i8259 domain before mapping the parent IRQ, such that the i8259 virq numbers become used before the parent interrupt controller gets a chance to use any of them. Signed-off-by: Paul Burton Acked-by: Thomas Gleixner Cc: Marc Zyngier Cc: Jason Cooper Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14269/ Signed-off-by: Ralf Baechle --- drivers/irqchip/irq-i8259.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index 6b304eb39bd2..85897fdc1527 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -370,13 +370,15 @@ int __init i8259_of_init(struct device_node *node, struct device_node *parent) struct irq_domain *domain; unsigned int parent_irq; + domain = __init_i8259_irqs(node); + parent_irq = irq_of_parse_and_map(node, 0); if (!parent_irq) { pr_err("Failed to map i8259 parent IRQ\n"); + irq_domain_remove(domain); return -ENODEV; } - domain = __init_i8259_irqs(node); irq_set_chained_handler_and_data(parent_irq, i8259_irq_dispatch, domain); return 0; -- cgit v1.2.3 From 19afc3d269fe66137ddb030b8ffdb8553066ba4a Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:19 +0100 Subject: irqchip: i8259: Allow platforms to override poll function The default i8259 polling function (i8259_irq) is nicely generic but is fairly costly. Platforms often provide an alternative means of polling for an i8259 interrupt, and when using the i8259 without device tree have typically just chained its parent interrupt to their own handler function. In order to allow for platform-specific polling functions to be used in cases where the driver is probed via device tree, provide an i8259_set_poll function that accepts a pointer to an alternative poll function that will override the default. Signed-off-by: Paul Burton Acked-by: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14270/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/i8259.h | 11 +++++++++++ drivers/irqchip/irq-i8259.c | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/irqchip') diff --git a/arch/mips/include/asm/i8259.h b/arch/mips/include/asm/i8259.h index a7fbcd6ed13c..b27fcc4ae474 100644 --- a/arch/mips/include/asm/i8259.h +++ b/arch/mips/include/asm/i8259.h @@ -43,6 +43,17 @@ extern void make_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); extern int i8259_of_init(struct device_node *node, struct device_node *parent); +/** + * i8159_set_poll() - Override the i8259 polling function + * @poll: pointer to platform-specific polling function + * + * Call this to override the generic i8259 polling function, which directly + * accesses i8259 registers, with a platform specific one which may be faster + * in cases where hardware provides a more optimal means of polling for an + * interrupt. + */ +extern void i8259_set_poll(int (*poll)(void)); + /* * Do the traditional i8259 interrupt polling thing. This is for the few * cases where no better interrupt acknowledge method is available and we diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index 85897fdc1527..1f4a3442342b 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -38,6 +38,7 @@ static void disable_8259A_irq(struct irq_data *d); static void enable_8259A_irq(struct irq_data *d); static void mask_and_ack_8259A(struct irq_data *d); static void init_8259A(int auto_eoi); +static int (*i8259_poll)(void) = i8259_irq; static struct irq_chip i8259A_chip = { .name = "XT-PIC", @@ -51,6 +52,11 @@ static struct irq_chip i8259A_chip = { * 8259A PIC functions to handle ISA devices: */ +void i8259_set_poll(int (*poll)(void)) +{ + i8259_poll = poll; +} + /* * This contains the irq mask for both 8259A irq controllers, */ @@ -355,7 +361,7 @@ void __init init_i8259_irqs(void) static void i8259_irq_dispatch(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - int hwirq = i8259_irq(); + int hwirq = i8259_poll(); unsigned int irq; if (hwirq < 0) -- cgit v1.2.3 From 5d2949ec86a54b73a6fc2557ef784e76c0d2cba9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 19 Sep 2016 22:21:20 +0100 Subject: irqchip: i8259: Remove unused i8259A_irq_pending The i8259A_irq_pending function is unused. Remove the dead code. Signed-off-by: Paul Burton Acked-by: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14271/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/i8259.h | 1 - drivers/irqchip/irq-i8259.c | 18 ------------------ 2 files changed, 19 deletions(-) (limited to 'drivers/irqchip') diff --git a/arch/mips/include/asm/i8259.h b/arch/mips/include/asm/i8259.h index b27fcc4ae474..32229c77906a 100644 --- a/arch/mips/include/asm/i8259.h +++ b/arch/mips/include/asm/i8259.h @@ -37,7 +37,6 @@ extern raw_spinlock_t i8259A_lock; -extern int i8259A_irq_pending(unsigned int irq); extern void make_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index 1f4a3442342b..1aec12c6d9ac 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -95,24 +95,6 @@ static void enable_8259A_irq(struct irq_data *d) raw_spin_unlock_irqrestore(&i8259A_lock, flags); } -int i8259A_irq_pending(unsigned int irq) -{ - unsigned int mask; - unsigned long flags; - int ret; - - irq -= I8259A_IRQ_BASE; - mask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - if (irq < 8) - ret = inb(PIC_MASTER_CMD) & mask; - else - ret = inb(PIC_SLAVE_CMD) & (mask >> 8); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - - return ret; -} - void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); -- cgit v1.2.3