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:
		@@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user