aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-08-01 04:13:46 -0400
committerPaul Mundt <lethal@linux-sh.org>2012-08-01 04:13:46 -0400
commit1d6a21b0a672fb29b01ccf397d478e0541e17716 (patch)
treecc4527286de39a1b70e0af1de16f8a664bea0118 /drivers/sh
parent2d534926205db9ffce4bbbde67cb9b2cee4b835c (diff)
sh: intc: initial irqdomain support.
Trivial support for irq domains, using either a linear map or radix tree depending on the vector layout. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh')
-rw-r--r--drivers/sh/intc/Kconfig4
-rw-r--r--drivers/sh/intc/Makefile2
-rw-r--r--drivers/sh/intc/core.c11
-rw-r--r--drivers/sh/intc/internals.h5
-rw-r--r--drivers/sh/intc/irqdomain.c68
5 files changed, 85 insertions, 5 deletions
diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig
index c88cbccc62b0..a305731742a9 100644
--- a/drivers/sh/intc/Kconfig
+++ b/drivers/sh/intc/Kconfig
@@ -1,3 +1,7 @@
1config SH_INTC
2 def_bool y
3 select IRQ_DOMAIN
4
1comment "Interrupt controller options" 5comment "Interrupt controller options"
2 6
3config INTC_USERIMASK 7config INTC_USERIMASK
diff --git a/drivers/sh/intc/Makefile b/drivers/sh/intc/Makefile
index 44f006d09471..54ec2a0643df 100644
--- a/drivers/sh/intc/Makefile
+++ b/drivers/sh/intc/Makefile
@@ -1,4 +1,4 @@
1obj-y := access.o chip.o core.o handle.o virq.o 1obj-y := access.o chip.o core.o handle.o irqdomain.o virq.o
2 2
3obj-$(CONFIG_INTC_BALANCING) += balancing.o 3obj-$(CONFIG_INTC_BALANCING) += balancing.o
4obj-$(CONFIG_INTC_USERIMASK) += userimask.o 4obj-$(CONFIG_INTC_USERIMASK) += userimask.o
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index 7e562ccb6997..2374468615ed 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -25,6 +25,7 @@
25#include <linux/stat.h> 25#include <linux/stat.h>
26#include <linux/interrupt.h> 26#include <linux/interrupt.h>
27#include <linux/sh_intc.h> 27#include <linux/sh_intc.h>
28#include <linux/irqdomain.h>
28#include <linux/device.h> 29#include <linux/device.h>
29#include <linux/syscore_ops.h> 30#include <linux/syscore_ops.h>
30#include <linux/list.h> 31#include <linux/list.h>
@@ -310,6 +311,8 @@ int __init register_intc_controller(struct intc_desc *desc)
310 311
311 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ 312 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
312 313
314 intc_irq_domain_init(d, hw);
315
313 /* register the vectors one by one */ 316 /* register the vectors one by one */
314 for (i = 0; i < hw->nr_vectors; i++) { 317 for (i = 0; i < hw->nr_vectors; i++) {
315 struct intc_vect *vect = hw->vectors + i; 318 struct intc_vect *vect = hw->vectors + i;
@@ -319,8 +322,8 @@ int __init register_intc_controller(struct intc_desc *desc)
319 if (!vect->enum_id) 322 if (!vect->enum_id)
320 continue; 323 continue;
321 324
322 res = irq_alloc_desc_at(irq, numa_node_id()); 325 res = irq_create_identity_mapping(d->domain, irq);
323 if (res != irq && res != -EEXIST) { 326 if (unlikely(res)) {
324 pr_err("can't get irq_desc for %d\n", irq); 327 pr_err("can't get irq_desc for %d\n", irq);
325 continue; 328 continue;
326 } 329 }
@@ -340,8 +343,8 @@ int __init register_intc_controller(struct intc_desc *desc)
340 * IRQ support, each vector still needs to have 343 * IRQ support, each vector still needs to have
341 * its own backing irq_desc. 344 * its own backing irq_desc.
342 */ 345 */
343 res = irq_alloc_desc_at(irq2, numa_node_id()); 346 res = irq_create_identity_mapping(d->domain, irq2);
344 if (res != irq2 && res != -EEXIST) { 347 if (unlikely(res)) {
345 pr_err("can't get irq_desc for %d\n", irq2); 348 pr_err("can't get irq_desc for %d\n", irq2);
346 continue; 349 continue;
347 } 350 }
diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h
index f034a979a16f..7dff08e2a071 100644
--- a/drivers/sh/intc/internals.h
+++ b/drivers/sh/intc/internals.h
@@ -1,5 +1,6 @@
1#include <linux/sh_intc.h> 1#include <linux/sh_intc.h>
2#include <linux/irq.h> 2#include <linux/irq.h>
3#include <linux/irqdomain.h>
3#include <linux/list.h> 4#include <linux/list.h>
4#include <linux/kernel.h> 5#include <linux/kernel.h>
5#include <linux/types.h> 6#include <linux/types.h>
@@ -66,6 +67,7 @@ struct intc_desc_int {
66 unsigned int nr_sense; 67 unsigned int nr_sense;
67 struct intc_window *window; 68 struct intc_window *window;
68 unsigned int nr_windows; 69 unsigned int nr_windows;
70 struct irq_domain *domain;
69 struct irq_chip chip; 71 struct irq_chip chip;
70 bool skip_suspend; 72 bool skip_suspend;
71}; 73};
@@ -187,6 +189,9 @@ unsigned long intc_get_ack_handle(unsigned int irq);
187void intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d, 189void intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d,
188 intc_enum enum_id, int enable); 190 intc_enum enum_id, int enable);
189 191
192/* irqdomain.c */
193void intc_irq_domain_init(struct intc_desc_int *d, struct intc_hw_desc *hw);
194
190/* virq.c */ 195/* virq.c */
191void intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d); 196void intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d);
192void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d); 197void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d);
diff --git a/drivers/sh/intc/irqdomain.c b/drivers/sh/intc/irqdomain.c
new file mode 100644
index 000000000000..3968f1c3c5c3
--- /dev/null
+++ b/drivers/sh/intc/irqdomain.c
@@ -0,0 +1,68 @@
1/*
2 * IRQ domain support for SH INTC subsystem
3 *
4 * Copyright (C) 2012 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#define pr_fmt(fmt) "intc: " fmt
11
12#include <linux/irqdomain.h>
13#include <linux/sh_intc.h>
14#include <linux/export.h>
15#include "internals.h"
16
17/**
18 * intc_irq_domain_evt_xlate() - Generic xlate for vectored IRQs.
19 *
20 * This takes care of exception vector to hwirq translation through
21 * by way of evt2irq() translation.
22 *
23 * Note: For platforms that use a flat vector space without INTEVT this
24 * basically just mimics irq_domain_xlate_onecell() by way of a nopped
25 * out evt2irq() implementation.
26 */
27static int intc_evt_xlate(struct irq_domain *d, struct device_node *ctrlr,
28 const u32 *intspec, unsigned int intsize,
29 unsigned long *out_hwirq, unsigned int *out_type)
30{
31 if (WARN_ON(intsize < 1))
32 return -EINVAL;
33
34 *out_hwirq = evt2irq(intspec[0]);
35 *out_type = IRQ_TYPE_NONE;
36
37 return 0;
38}
39
40static const struct irq_domain_ops intc_evt_ops = {
41 .xlate = intc_evt_xlate,
42};
43
44void __init intc_irq_domain_init(struct intc_desc_int *d,
45 struct intc_hw_desc *hw)
46{
47 unsigned int irq_base, irq_end;
48
49 /*
50 * Quick linear revmap check
51 */
52 irq_base = evt2irq(hw->vectors[0].vect);
53 irq_end = evt2irq(hw->vectors[hw->nr_vectors - 1].vect);
54
55 /*
56 * Linear domains have a hard-wired assertion that IRQs start at
57 * 0 in order to make some performance optimizations. Lamely
58 * restrict the linear case to these conditions here, taking the
59 * tree penalty for linear cases with non-zero hwirq bases.
60 */
61 if (irq_base == 0 && irq_end == (irq_base + hw->nr_vectors - 1))
62 d->domain = irq_domain_add_linear(NULL, hw->nr_vectors,
63 &intc_evt_ops, NULL);
64 else
65 d->domain = irq_domain_add_tree(NULL, &intc_evt_ops, NULL);
66
67 BUG_ON(!d->domain);
68}