diff options
Diffstat (limited to 'target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch')
-rw-r--r-- | target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch | 304 |
1 files changed, 53 insertions, 251 deletions
diff --git a/target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch b/target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch index 5a8c83c5e1..4345d3e0dd 100644 --- a/target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch +++ b/target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch @@ -17,8 +17,6 @@ Signed-off-by: Hans de Goede <hdegoede@redhat.com> kernel/irq/manage.c | 2 +- 4 files changed, 45 insertions(+), 9 deletions(-) -diff --git a/include/linux/irq.h b/include/linux/irq.h -index 7dc1003..0f036fb 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -349,6 +349,8 @@ struct irq_chip { @@ -38,8 +36,6 @@ index 7dc1003..0f036fb 100644 }; /* This include will go away once we isolated irq_desc usage to core code */ -diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c -index dc04c16..6397df2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc) @@ -62,7 +58,7 @@ index dc04c16..6397df2 100644 /* * handle_nested_irq - Handle a nested irq from a irq thread * @irq: the interrupt number -@@ -435,6 +448,27 @@ static inline void preflow_handler(struct irq_desc *desc) +@@ -435,6 +448,27 @@ static inline void preflow_handler(struc static inline void preflow_handler(struct irq_desc *desc) { } #endif @@ -90,7 +86,7 @@ index dc04c16..6397df2 100644 /** * handle_fasteoi_irq - irq handler for transparent controllers * @irq: the interrupt number -@@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } +@@ -448,6 +482,8 @@ static inline void preflow_handler(struc void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) { @@ -99,7 +95,7 @@ index dc04c16..6397df2 100644 raw_spin_lock(&desc->lock); if (unlikely(irqd_irq_inprogress(&desc->irq_data))) -@@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) +@@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, str preflow_handler(desc); handle_irq_event(desc); @@ -122,11 +118,9 @@ index dc04c16..6397df2 100644 } /** -diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h -index 001fa5b..e98bb56 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h -@@ -73,6 +73,7 @@ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu); +@@ -73,6 +73,7 @@ extern void irq_percpu_enable(struct irq extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu); extern void mask_irq(struct irq_desc *desc); extern void unmask_irq(struct irq_desc *desc); @@ -134,11 +128,9 @@ index 001fa5b..e98bb56 100644 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); -diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c -index d3bf660..7593958 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c -@@ -718,7 +718,7 @@ static void irq_finalize_oneshot(struct irq_desc *desc, +@@ -713,7 +713,7 @@ again: if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data)) @@ -147,35 +139,56 @@ index d3bf660..7593958 100644 out_unlock: raw_spin_unlock_irq(&desc->lock); --- -2.0.3 - -From d000f9a5348e6d6c8b620a9c2d0b97c69d6d6153 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Tue, 11 Mar 2014 16:47:46 +0100 -Subject: [PATCH] irqchip: sun4i: Fix irq 0 not working - -SUN4I_IRQ_VECTOR_REG containing 0 can mean one of 3 things: -1) no more irqs pending -2) irq 0 pending -3) spurious irq - -So if we immediately get a reading of 0, check the irq-pending reg -to differentiate between 2 and 3. We only do this once to avoid -the extra check in the common case of 1) hapening after having -read the vector-reg once. - -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> ---- - drivers/irqchip/irq-sun4i.c | 18 ++++++++++++++++-- - 1 file changed, 16 insertions(+), 2 deletions(-) - -diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c -index a5438d8..5c25048 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c -@@ -140,10 +140,24 @@ static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *re +@@ -41,13 +41,11 @@ static asmlinkage void __exception_irq_e + static void sun4i_irq_ack(struct irq_data *irqd) + { + unsigned int irq = irqd_to_hwirq(irqd); +- unsigned int irq_off = irq % 32; +- int reg = irq / 32; +- u32 val; + +- val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); +- writel(val | (1 << irq_off), +- sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); ++ if (irq != 0) ++ return; /* Only IRQ 0 / the ENMI needs to be acked */ ++ ++ writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)); + } + + static void sun4i_irq_mask(struct irq_data *irqd) +@@ -76,16 +74,16 @@ static void sun4i_irq_unmask(struct irq_ + + static struct irq_chip sun4i_irq_chip = { + .name = "sun4i_irq", +- .irq_ack = sun4i_irq_ack, ++ .irq_eoi = sun4i_irq_ack, + .irq_mask = sun4i_irq_mask, + .irq_unmask = sun4i_irq_unmask, ++ .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, + }; + + static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) + { +- irq_set_chip_and_handler(virq, &sun4i_irq_chip, +- handle_level_irq); ++ irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + + return 0; +@@ -109,7 +107,7 @@ static int __init sun4i_of_init(struct d + writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); + writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); + +- /* Mask all the interrupts */ ++ /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */ + writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); + writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); + writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); +@@ -140,10 +138,24 @@ static asmlinkage void __exception_irq_e { u32 irq, hwirq; @@ -202,214 +215,3 @@ index a5438d8..5c25048 100644 - } + } while (hwirq != 0); } --- -2.0.3 - -From b37587009473582d9fc080e8b8b99b67b0077a90 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Tue, 11 Mar 2014 16:53:23 +0100 -Subject: [PATCH] irqchip: sun4i: Fix a comment about mask register - initialization - -The comment was claiming that we were masking all irqs, while the code actually -*un*masks all of them. - -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> ---- - drivers/irqchip/irq-sun4i.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c -index 5c25048..8a2fbee 100644 ---- a/drivers/irqchip/irq-sun4i.c -+++ b/drivers/irqchip/irq-sun4i.c -@@ -109,7 +109,7 @@ static int __init sun4i_of_init(struct device_node *node, - writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); - writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); - -- /* Mask all the interrupts */ -+ /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */ - writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); - writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); - writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); --- -2.0.3 - -From c8865ee82b74b2d95339370972a0d9bfdbac09cf Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Wed, 12 Mar 2014 17:43:45 +0100 -Subject: [PATCH] irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ 0 - -All IRQs except for IRQ 0 seem to not need acking, so drop acking for them. - -The ENMI needs to have the ack done *after* clearing the interrupt source, -otherwise we will get a spurious interrupt for each real interrupt. - -So use the new IRQCHIP_EOI_THREADED flag for this in combination with -handle_fasteoi_irq. This uses a separate irq_chip struct for IRQ 0, -since we only want this behavior for IRQ 0. - -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - drivers/irqchip/irq-sun4i.c | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c -index 8a2fbee..a0ed1ea 100644 ---- a/drivers/irqchip/irq-sun4i.c -+++ b/drivers/irqchip/irq-sun4i.c -@@ -76,16 +76,29 @@ static void sun4i_irq_unmask(struct irq_data *irqd) - - static struct irq_chip sun4i_irq_chip = { - .name = "sun4i_irq", -- .irq_ack = sun4i_irq_ack, - .irq_mask = sun4i_irq_mask, - .irq_unmask = sun4i_irq_unmask, - }; - -+/* IRQ 0 / the ENMI needs a late eoi call */ -+static struct irq_chip sun4i_irq_chip_enmi = { -+ .name = "sun4i_irq", -+ .irq_eoi = sun4i_irq_ack, -+ .irq_mask = sun4i_irq_mask, -+ .irq_unmask = sun4i_irq_unmask, -+ .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, -+}; -+ - static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) - { -- irq_set_chip_and_handler(virq, &sun4i_irq_chip, -- handle_level_irq); -+ if (hw == 0) -+ irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi, -+ handle_fasteoi_irq); -+ else -+ irq_set_chip_and_handler(virq, &sun4i_irq_chip, -+ handle_level_irq); -+ - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); - - return 0; --- -2.0.3 - -From f8b4347aa12d7a30aa1d3e5bfcdccece52d17af3 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Thu, 13 Mar 2014 19:38:26 +0100 -Subject: [PATCH] irqchip: sun4i: Use handle_fasteoi_irq for all interrupts - -Since the sun4i irq chip does not require any action and clears the interrupt -when the level goes back to inactive, we don't need to mask / unmask for -non oneshot IRQs, to achieve this we make sun4i_irq_ack a nop for all irqs -except irq 0 and use handle_fasteoi_irq for all interrupts. - -Now there might be a case when the device reactivates the interrupt -before the RETI. But that does not matter as we run the primary -interrupt handlers with interrupts disabled. - -This also allows us to get rid of needing to use 2 irq_chip structs, this -means that the IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED will now influence -all interrupts rather then just irq 0, but that does not matter as the eoi -is now a nop anyways for all interrupts but irq 0. - -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> ---- - drivers/irqchip/irq-sun4i.c | 18 ++++-------------- - 1 file changed, 4 insertions(+), 14 deletions(-) - -diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c -index a0ed1ea..6a8c88d 100644 ---- a/drivers/irqchip/irq-sun4i.c -+++ b/drivers/irqchip/irq-sun4i.c -@@ -45,6 +45,9 @@ static void sun4i_irq_ack(struct irq_data *irqd) - int reg = irq / 32; - u32 val; - -+ if (irq != 0) -+ return; /* Only IRQ 0 / the ENMI needs to be acked */ -+ - val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); - writel(val | (1 << irq_off), - sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); -@@ -76,13 +79,6 @@ static void sun4i_irq_unmask(struct irq_data *irqd) - - static struct irq_chip sun4i_irq_chip = { - .name = "sun4i_irq", -- .irq_mask = sun4i_irq_mask, -- .irq_unmask = sun4i_irq_unmask, --}; -- --/* IRQ 0 / the ENMI needs a late eoi call */ --static struct irq_chip sun4i_irq_chip_enmi = { -- .name = "sun4i_irq", - .irq_eoi = sun4i_irq_ack, - .irq_mask = sun4i_irq_mask, - .irq_unmask = sun4i_irq_unmask, -@@ -92,13 +88,7 @@ static struct irq_chip sun4i_irq_chip_enmi = { - static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) - { -- if (hw == 0) -- irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi, -- handle_fasteoi_irq); -- else -- irq_set_chip_and_handler(virq, &sun4i_irq_chip, -- handle_level_irq); -- -+ irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq); - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); - - return 0; --- -2.0.3 - -From de39bc31eaa554bd044e6adefacd3da6da5bf6e3 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Thu, 13 Mar 2014 20:41:20 +0100 -Subject: [PATCH] irqchip: sun4i: simplify sun4i_irq_ack - -Now that we only ack irq 0 the code can be simplified a lot. - -Also switch from read / modify / write to a simple write clear: -1) This is what the android code does (it has a hack for acking irq 0 - in its unmask code doing this) -2) read / modify / write simply does not make sense for an irq status - register like this, if the other bits are writeable (and the data sheet says - they are not) they should be write 1 to clear, since otherwise a read / - modify / write can race with a device raising an interrupt and then clear - the pending bit unintentionally - -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> ---- - drivers/irqchip/irq-sun4i.c | 7 +------ - 1 file changed, 1 insertion(+), 6 deletions(-) - -diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c -index 6a8c88d..75615b5 100644 ---- a/drivers/irqchip/irq-sun4i.c -+++ b/drivers/irqchip/irq-sun4i.c -@@ -41,16 +41,11 @@ static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *re - static void sun4i_irq_ack(struct irq_data *irqd) - { - unsigned int irq = irqd_to_hwirq(irqd); -- unsigned int irq_off = irq % 32; -- int reg = irq / 32; -- u32 val; - - if (irq != 0) - return; /* Only IRQ 0 / the ENMI needs to be acked */ - -- val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); -- writel(val | (1 << irq_off), -- sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); -+ writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)); - } - - static void sun4i_irq_mask(struct irq_data *irqd) --- -2.0.3 - |