|
@@ -376,3 +376,89 @@ void __init __vic_init(void __iomem *base, int irq_start,
|
|
|
switch(vendor) {
|
|
|
case AMBA_VENDOR_ST:
|
|
|
vic_init_st(base, irq_start, vic_sources, node);
|
|
|
+ return;
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
|
|
|
+ /* fall through */
|
|
|
+ case AMBA_VENDOR_ARM:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Disable all interrupts initially. */
|
|
|
+ vic_disable(base);
|
|
|
+
|
|
|
+ /* Make sure we clear all existing interrupts */
|
|
|
+ vic_clear_interrupts(base);
|
|
|
+
|
|
|
+ vic_init2(base);
|
|
|
+
|
|
|
+ vic_register(base, irq_start, vic_sources, resume_sources, node);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * vic_init() - initialise a vectored interrupt controller
|
|
|
+ * @base: iomem base address
|
|
|
+ * @irq_start: starting interrupt number, must be muliple of 32
|
|
|
+ * @vic_sources: bitmask of interrupt sources to allow
|
|
|
+ * @resume_sources: bitmask of interrupt sources to allow for resume
|
|
|
+ */
|
|
|
+void __init vic_init(void __iomem *base, unsigned int irq_start,
|
|
|
+ u32 vic_sources, u32 resume_sources)
|
|
|
+{
|
|
|
+ __vic_init(base, irq_start, vic_sources, resume_sources, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_OF
|
|
|
+int __init vic_of_init(struct device_node *node, struct device_node *parent)
|
|
|
+{
|
|
|
+ void __iomem *regs;
|
|
|
+
|
|
|
+ if (WARN(parent, "non-root VICs are not supported"))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ regs = of_iomap(node, 0);
|
|
|
+ if (WARN_ON(!regs))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Passing 0 as first IRQ makes the simple domain allocate descriptors
|
|
|
+ */
|
|
|
+ __vic_init(regs, 0, ~0, ~0, node);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif /* CONFIG OF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Handle each interrupt in a single VIC. Returns non-zero if we've
|
|
|
+ * handled at least one interrupt. This reads the status register
|
|
|
+ * before handling each interrupt, which is necessary given that
|
|
|
+ * handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
|
|
|
+ */
|
|
|
+static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
|
|
|
+{
|
|
|
+ u32 stat, irq;
|
|
|
+ int handled = 0;
|
|
|
+
|
|
|
+ while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
|
|
|
+ irq = ffs(stat) - 1;
|
|
|
+ handle_IRQ(irq_find_mapping(vic->domain, irq), regs);
|
|
|
+ handled = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return handled;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Keep iterating over all registered VIC's until there are no pending
|
|
|
+ * interrupts.
|
|
|
+ */
|
|
|
+asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
|
|
|
+{
|
|
|
+ int i, handled;
|
|
|
+
|
|
|
+ do {
|
|
|
+ for (i = 0, handled = 0; i < vic_id; ++i)
|
|
|
+ handled |= handle_one_vic(&vic_devices[i], regs);
|
|
|
+ } while (handled);
|
|
|
+}
|