mcs814x: fix interrupt handling

Switch to generich chip irqs/irq domains.
Interrupts were broken since kernel 3.14. dLAN USB extender is now
booting again.

Signed-off-by: Günther Kelleter <guenther.kelleter@devolo.de>

SVN-Revision: 46647
This commit is contained in:
John Crispin 2015-08-17 06:16:08 +00:00
parent a8d7c5c8de
commit d8ec3ee77d
2 changed files with 28 additions and 23 deletions

View File

@ -17,6 +17,7 @@
#include <mach/mcs814x.h> #include <mach/mcs814x.h>
static void __iomem *mcs814x_intc_base; static void __iomem *mcs814x_intc_base;
static struct irq_domain *domain;
static void __init mcs814x_alloc_gc(void __iomem *base, unsigned int irq_start, static void __init mcs814x_alloc_gc(void __iomem *base, unsigned int irq_start,
unsigned int num) unsigned int num)
@ -24,11 +25,15 @@ static void __init mcs814x_alloc_gc(void __iomem *base, unsigned int irq_start,
struct irq_chip_generic *gc; struct irq_chip_generic *gc;
struct irq_chip_type *ct; struct irq_chip_type *ct;
gc = irq_alloc_generic_chip("mcs814x-intc", 1, if (irq_alloc_domain_generic_chips(domain, num, 1, "mcs814x-intc", handle_level_irq,
irq_start, base, handle_level_irq); IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0))
if (!gc) panic("unable to allocate domain generic irq chip");
panic("unable to allocate generic irq chip");
gc = irq_get_domain_generic_chip(domain, irq_start);
if (!gc)
panic("unable to get generic irq chip");
gc->reg_base = base;
ct = gc->chip_types; ct = gc->chip_types;
ct->chip.irq_ack = irq_gc_unmask_enable_reg; ct->chip.irq_ack = irq_gc_unmask_enable_reg;
ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_mask = irq_gc_mask_clr_bit;
@ -36,9 +41,6 @@ static void __init mcs814x_alloc_gc(void __iomem *base, unsigned int irq_start,
ct->regs.mask = MCS814X_IRQ_MASK; ct->regs.mask = MCS814X_IRQ_MASK;
ct->regs.enable = MCS814X_IRQ_ICR; ct->regs.enable = MCS814X_IRQ_ICR;
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST, 0);
/* Clear all interrupts */ /* Clear all interrupts */
writel_relaxed(0xffffffff, base + MCS814X_IRQ_ICR); writel_relaxed(0xffffffff, base + MCS814X_IRQ_ICR);
} }
@ -58,7 +60,7 @@ asmlinkage void __exception_irq_entry mcs814x_handle_irq(struct pt_regs *regs)
/* clear the interrupt */ /* clear the interrupt */
__raw_writel(status, mcs814x_intc_base + MCS814X_IRQ_STS0); __raw_writel(status, mcs814x_intc_base + MCS814X_IRQ_STS0);
/* call the generic handler */ /* call the generic handler */
handle_IRQ(irq, regs); handle_domain_irq(domain, irq, regs);
} while (1); } while (1);
} }
@ -80,7 +82,10 @@ void __init mcs814x_of_irq_init(void)
if (!mcs814x_intc_base) if (!mcs814x_intc_base)
panic("unable to map intc cpu registers\n"); panic("unable to map intc cpu registers\n");
irq_domain_add_simple(np, 32, 0, &irq_generic_chip_ops, NULL); domain = irq_domain_add_linear(np, 32, &irq_generic_chip_ops, NULL);
if (!domain)
panic("unable to add irq domain\n");
irq_set_default_host(domain);
of_node_put(np); of_node_put(np);

View File

@ -15,6 +15,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <mach/mcs814x.h> #include <mach/mcs814x.h>
@ -71,21 +72,15 @@ static irqreturn_t mcs814x_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static struct irqaction mcs814x_timer_irq = {
.name = "mcs814x-timer",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = mcs814x_timer_interrupt,
};
static struct of_device_id mcs814x_timer_ids[] = { static struct of_device_id mcs814x_timer_ids[] = {
{ .compatible = "moschip,mcs814x-timer" }, { .compatible = "moschip,mcs814x-timer" },
{ /* sentinel */ }, { /* sentinel */ },
}; };
static void __init mcs814x_of_timer_init(void) static int __init mcs814x_of_timer_init(void)
{ {
struct device_node *np; struct device_node *np;
const unsigned int *intspec; int irq;
np = of_find_matching_node(NULL, mcs814x_timer_ids); np = of_find_matching_node(NULL, mcs814x_timer_ids);
if (!np) if (!np)
@ -95,16 +90,17 @@ static void __init mcs814x_of_timer_init(void)
if (!mcs814x_timer_base) if (!mcs814x_timer_base)
panic("unable to remap timer cpu registers"); panic("unable to remap timer cpu registers");
intspec = of_get_property(np, "interrupts", NULL); irq = irq_of_parse_and_map(np, 0);
if (!intspec) if (!irq)
panic("no interrupts property for timer"); panic("no interrupts property/mapping failed for timer");
mcs814x_timer_irq.irq = be32_to_cpup(intspec); return irq;
} }
void __init mcs814x_timer_init(void) void __init mcs814x_timer_init(void)
{ {
struct clk *clk; struct clk *clk;
int irq;
arch_gettimeoffset = mcs814x_gettimeoffset; arch_gettimeoffset = mcs814x_gettimeoffset;
@ -114,7 +110,7 @@ void __init mcs814x_timer_init(void)
clock_rate = clk_get_rate(clk); clock_rate = clk_get_rate(clk);
mcs814x_of_timer_init(); irq = mcs814x_of_timer_init();
pr_info("Timer frequency: %d (kHz)\n", clock_rate / 1000); pr_info("Timer frequency: %d (kHz)\n", clock_rate / 1000);
@ -125,7 +121,11 @@ void __init mcs814x_timer_init(void)
writel_relaxed(timer_reload_value, mcs814x_timer_base + TIMER_VAL); writel_relaxed(timer_reload_value, mcs814x_timer_base + TIMER_VAL);
last_reload = timer_reload_value; last_reload = timer_reload_value;
setup_irq(mcs814x_timer_irq.irq, &mcs814x_timer_irq); if (request_irq(irq, mcs814x_timer_interrupt,
IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
"mcs814x-timer", NULL))
panic("unable to request timer0 irq %d", irq);
/* enable timer, stop timer in debug mode */ /* enable timer, stop timer in debug mode */
writel_relaxed(TIMER_CTL_EN | TIMER_CTL_DBG, writel_relaxed(TIMER_CTL_EN | TIMER_CTL_DBG,
mcs814x_timer_base + TIMER_CTL); mcs814x_timer_base + TIMER_CTL);