summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@libc.org>2016-08-10 14:59:00 +0000
committerRich Felker <dalias@libc.org>2016-08-10 14:59:36 +0000
commit76c8129e8ebc4408f209b4ac4ee843356db1b5ae (patch)
treecc157c508a1d3dcff75f29723465c37f02da560c
parent7b6a9209d0588d7ca1e3d1f7be6c197d64dd67bc (diff)
downloadlinux-sh-76c8129e8ebc4408f209b4ac4ee843356db1b5ae.tar.gz
irqchip/jcore: backport changes sent upstream for 4.8
Signed-off-by: Rich Felker <dalias@libc.org>
-rw-r--r--drivers/irqchip/irq-jcore-aic.c95
1 files changed, 47 insertions, 48 deletions
diff --git a/drivers/irqchip/irq-jcore-aic.c b/drivers/irqchip/irq-jcore-aic.c
index 1348cdb7ffe8..5e5e3bb7d3c7 100644
--- a/drivers/irqchip/irq-jcore-aic.c
+++ b/drivers/irqchip/irq-jcore-aic.c
@@ -12,35 +12,31 @@
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
-#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#define AIC1_INTPRI 8
+#define JCORE_AIC_MAX_HWIRQ 127
+#define JCORE_AIC1_MIN_HWIRQ 16
+#define JCORE_AIC2_MIN_HWIRQ 64
-static struct aic_data {
- unsigned char __iomem *base;
- u32 cpu_offset;
- struct irq_chip chip;
- struct irq_domain *domain;
- struct notifier_block nb;
-} aic_data;
+#define JCORE_AIC1_INTPRI_REG 8
+
+static struct irq_chip jcore_aic;
-static int aic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
+static int jcore_aic_irqdomain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
- struct aic_data *aic = d->host_data;
+ struct irq_chip *aic = d->host_data;
- irq_set_chip_data(irq, aic);
- irq_set_chip_and_handler(irq, &aic->chip, handle_simple_irq);
- irq_set_probe(irq);
+ irq_set_chip_and_handler(irq, aic, handle_simple_irq);
return 0;
}
-static const struct irq_domain_ops aic_irqdomain_ops = {
- .map = aic_irqdomain_map,
+static const struct irq_domain_ops jcore_aic_irqdomain_ops = {
+ .map = jcore_aic_irqdomain_map,
.xlate = irq_domain_xlate_onecell,
};
@@ -48,45 +44,48 @@ static void noop(struct irq_data *data)
{
}
-static void aic1_localenable(struct aic_data *aic)
-{
- unsigned cpu = smp_processor_id();
- pr_info("Local AIC enable on cpu %u\n", cpu);
- writel(0xffffffff, aic->base + cpu * aic->cpu_offset + AIC1_INTPRI);
-}
-
-static int aic1_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
-{
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_STARTING:
- aic1_localenable(container_of(self, struct aic_data, nb));
- break;
- }
- return NOTIFY_OK;
-}
-
int __init aic_irq_of_init(struct device_node *node, struct device_node *parent)
{
- struct aic_data *aic = &aic_data;
-
- aic->base = of_iomap(node, 0);
- of_property_read_u32(node, "cpu-offset", &aic->cpu_offset);
+ unsigned min_irq = JCORE_AIC2_MIN_HWIRQ;
+ unsigned dom_sz = JCORE_AIC_MAX_HWIRQ+1;
+ struct irq_domain *domain;
- pr_info("Initializing J-Core AIC at %p\n", aic->base);
+ pr_info("Initializing J-Core AIC\n");
+ /* AIC1 needs priority initialization to receive interrupts. */
if (of_device_is_compatible(node, "jcore,aic1")) {
- /* For aic1, need to enabled zero-priority-by-default irqs */
- aic->nb.notifier_call = aic1_cpu_notify;
- register_cpu_notifier(&aic->nb);
- aic1_localenable(aic);
+ unsigned cpu;
+
+ for_each_present_cpu(cpu) {
+ void __iomem *base = of_iomap(node, cpu);
+
+ if (!base) {
+ pr_err("Unable to map AIC for cpu %u\n", cpu);
+ return -ENOMEM;
+ }
+ __raw_writel(0xffffffff, base + JCORE_AIC1_INTPRI_REG);
+ iounmap(base);
+ }
+ min_irq = JCORE_AIC1_MIN_HWIRQ;
}
- aic->chip.name = node->name;
- aic->chip.irq_mask = noop;
- aic->chip.irq_unmask = noop;
-
- aic->domain = irq_domain_add_linear(node, 128, &aic_irqdomain_ops, aic);
- irq_create_strict_mappings(aic->domain, 16, 16, 112);
+ /*
+ * The irq chip framework requires either mask/unmask or enable/disable
+ * function pointers to be provided, but the hardware does not have any
+ * such mechanism; the only interrupt masking is at the cpu level and
+ * it affects all interrupts. We provide dummy mask/unmask. The hardware
+ * handles all interrupt control and clears pending status when the cpu
+ * accepts the interrupt.
+ */
+ jcore_aic.irq_mask = noop;
+ jcore_aic.irq_unmask = noop;
+ jcore_aic.name = "AIC";
+
+ domain = irq_domain_add_linear(node, dom_sz, &jcore_aic_irqdomain_ops,
+ &jcore_aic);
+ if (!domain)
+ return -ENOMEM;
+ irq_create_strict_mappings(domain, min_irq, min_irq, dom_sz - min_irq);
return 0;
}