aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/include/asm/prom.h5
-rw-r--r--arch/arm/kernel/devtree.c14
-rw-r--r--include/linux/irq.h6
-rw-r--r--include/linux/irqdomain.h81
-rw-r--r--include/linux/of_irq.h4
-rw-r--r--kernel/irq/Kconfig4
-rw-r--r--kernel/irq/Makefile1
-rw-r--r--kernel/irq/irqdomain.c122
9 files changed, 219 insertions, 19 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1478c6171b00..8ac7b996038c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1682,6 +1682,7 @@ config USE_OF
1682 bool "Flattened Device Tree support" 1682 bool "Flattened Device Tree support"
1683 select OF 1683 select OF
1684 select OF_EARLY_FLATTREE 1684 select OF_EARLY_FLATTREE
1685 select IRQ_DOMAIN
1685 help 1686 help
1686 Include support for flattened device tree machine descriptions. 1687 Include support for flattened device tree machine descriptions.
1687 1688
diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h
index 11b8708fc4db..6f65ca86a5ec 100644
--- a/arch/arm/include/asm/prom.h
+++ b/arch/arm/include/asm/prom.h
@@ -16,11 +16,6 @@
16#include <asm/setup.h> 16#include <asm/setup.h>
17#include <asm/irq.h> 17#include <asm/irq.h>
18 18
19static inline void irq_dispose_mapping(unsigned int virq)
20{
21 return;
22}
23
24extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys); 19extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
25extern void arm_dt_memblock_reserve(void); 20extern void arm_dt_memblock_reserve(void);
26 21
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 0cdd7b456cb2..1a33e9d6bb1f 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -132,17 +132,3 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
132 132
133 return mdesc_best; 133 return mdesc_best;
134} 134}
135
136/**
137 * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
138 *
139 * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
140 * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not
141 * supported.
142 */
143unsigned int irq_create_of_mapping(struct device_node *controller,
144 const u32 *intspec, unsigned int intsize)
145{
146 return intspec[0];
147}
148EXPORT_SYMBOL_GPL(irq_create_of_mapping);
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 5f695041090c..87a06f345bd2 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -108,14 +108,18 @@ enum {
108}; 108};
109 109
110struct msi_desc; 110struct msi_desc;
111struct irq_domain;
111 112
112/** 113/**
113 * struct irq_data - per irq and irq chip data passed down to chip functions 114 * struct irq_data - per irq and irq chip data passed down to chip functions
114 * @irq: interrupt number 115 * @irq: interrupt number
116 * @hwirq: hardware interrupt number, local to the interrupt domain
115 * @node: node index useful for balancing 117 * @node: node index useful for balancing
116 * @state_use_accessors: status information for irq chip functions. 118 * @state_use_accessors: status information for irq chip functions.
117 * Use accessor functions to deal with it 119 * Use accessor functions to deal with it
118 * @chip: low level interrupt hardware access 120 * @chip: low level interrupt hardware access
121 * @domain: Interrupt translation domain; responsible for mapping
122 * between hwirq number and linux irq number.
119 * @handler_data: per-IRQ data for the irq_chip methods 123 * @handler_data: per-IRQ data for the irq_chip methods
120 * @chip_data: platform-specific per-chip private data for the chip 124 * @chip_data: platform-specific per-chip private data for the chip
121 * methods, to allow shared chip implementations 125 * methods, to allow shared chip implementations
@@ -128,9 +132,11 @@ struct msi_desc;
128 */ 132 */
129struct irq_data { 133struct irq_data {
130 unsigned int irq; 134 unsigned int irq;
135 unsigned long hwirq;
131 unsigned int node; 136 unsigned int node;
132 unsigned int state_use_accessors; 137 unsigned int state_use_accessors;
133 struct irq_chip *chip; 138 struct irq_chip *chip;
139 struct irq_domain *domain;
134 void *handler_data; 140 void *handler_data;
135 void *chip_data; 141 void *chip_data;
136 struct msi_desc *msi_desc; 142 struct msi_desc *msi_desc;
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
new file mode 100644
index 000000000000..8f2c10a784a4
--- /dev/null
+++ b/include/linux/irqdomain.h
@@ -0,0 +1,81 @@
1/*
2 * irq_domain - IRQ translation domains
3 *
4 * Translation infrastructure between hw and linux irq numbers. This is
5 * helpful for interrupt controllers to implement mapping between hardware
6 * irq numbers and the Linux irq number space.
7 *
8 * irq_domains also have a hook for translating device tree interrupt
9 * representation into a hardware irq number that can be mapped back to a
10 * Linux irq number without any extra platform support code.
11 *
12 * irq_domain is expected to be embedded in an interrupt controller's private
13 * data structure.
14 */
15#ifndef _LINUX_IRQDOMAIN_H
16#define _LINUX_IRQDOMAIN_H
17
18#include <linux/irq.h>
19
20#ifdef CONFIG_IRQ_DOMAIN
21struct device_node;
22struct irq_domain;
23
24/**
25 * struct irq_domain_ops - Methods for irq_domain objects
26 * @to_irq: (optional) given a local hardware irq number, return the linux
27 * irq number. If to_irq is not implemented, then the irq_domain
28 * will use this translation: irq = (domain->irq_base + hwirq)
29 * @dt_translate: Given a device tree node and interrupt specifier, decode
30 * the hardware irq number and linux irq type value.
31 */
32struct irq_domain_ops {
33 unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
34
35#ifdef CONFIG_OF
36 int (*dt_translate)(struct irq_domain *d, struct device_node *node,
37 const u32 *intspec, unsigned int intsize,
38 unsigned long *out_hwirq, unsigned int *out_type);
39#endif /* CONFIG_OF */
40};
41
42/**
43 * struct irq_domain - Hardware interrupt number translation object
44 * @list: Element in global irq_domain list.
45 * @irq_base: Start of irq_desc range assigned to the irq_domain. The creator
46 * of the irq_domain is responsible for allocating the array of
47 * irq_desc structures.
48 * @nr_irq: Number of irqs managed by the irq domain
49 * @ops: pointer to irq_domain methods
50 * @priv: private data pointer for use by owner. Not touched by irq_domain
51 * core code.
52 * @of_node: (optional) Pointer to device tree nodes associated with the
53 * irq_domain. Used when decoding device tree interrupt specifiers.
54 */
55struct irq_domain {
56 struct list_head list;
57 unsigned int irq_base;
58 unsigned int nr_irq;
59 const struct irq_domain_ops *ops;
60 void *priv;
61 struct device_node *of_node;
62};
63
64/**
65 * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
66 *
67 * Returns the linux irq number associated with a hardware irq. By default,
68 * the mapping is irq == domain->irq_base + hwirq, but this mapping can
69 * be overridden if the irq_domain implements a .to_irq() hook.
70 */
71static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
72 unsigned long hwirq)
73{
74 return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq;
75}
76
77extern void irq_domain_add(struct irq_domain *domain);
78extern void irq_domain_del(struct irq_domain *domain);
79#endif /* CONFIG_IRQ_DOMAIN */
80
81#endif /* _LINUX_IRQDOMAIN_H */
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index e6955f5d1f08..cd2e61ce4e83 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -63,6 +63,9 @@ extern int of_irq_map_one(struct device_node *device, int index,
63extern unsigned int irq_create_of_mapping(struct device_node *controller, 63extern unsigned int irq_create_of_mapping(struct device_node *controller,
64 const u32 *intspec, 64 const u32 *intspec,
65 unsigned int intsize); 65 unsigned int intsize);
66#ifdef CONFIG_IRQ_DOMAIN
67extern void irq_dispose_mapping(unsigned int irq);
68#endif
66extern int of_irq_to_resource(struct device_node *dev, int index, 69extern int of_irq_to_resource(struct device_node *dev, int index,
67 struct resource *r); 70 struct resource *r);
68extern int of_irq_count(struct device_node *dev); 71extern int of_irq_count(struct device_node *dev);
@@ -70,6 +73,7 @@ extern int of_irq_to_resource_table(struct device_node *dev,
70 struct resource *res, int nr_irqs); 73 struct resource *res, int nr_irqs);
71extern struct device_node *of_irq_find_parent(struct device_node *child); 74extern struct device_node *of_irq_find_parent(struct device_node *child);
72 75
76
73#endif /* CONFIG_OF_IRQ */ 77#endif /* CONFIG_OF_IRQ */
74#endif /* CONFIG_OF */ 78#endif /* CONFIG_OF */
75#endif /* __OF_IRQ_H */ 79#endif /* __OF_IRQ_H */
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index d1d051b38e0b..5a38bf4de641 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -52,6 +52,10 @@ config IRQ_EDGE_EOI_HANDLER
52config GENERIC_IRQ_CHIP 52config GENERIC_IRQ_CHIP
53 bool 53 bool
54 54
55# Generic irq_domain hw <--> linux irq number translation
56config IRQ_DOMAIN
57 bool
58
55# Support forced irq threading 59# Support forced irq threading
56config IRQ_FORCED_THREADING 60config IRQ_FORCED_THREADING
57 bool 61 bool
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index 73290056cfb6..fff17381f0af 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -2,6 +2,7 @@
2obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o 2obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
3obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o 3obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
4obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o 4obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
5obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
5obj-$(CONFIG_PROC_FS) += proc.o 6obj-$(CONFIG_PROC_FS) += proc.o
6obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o 7obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
7obj-$(CONFIG_PM_SLEEP) += pm.o 8obj-$(CONFIG_PM_SLEEP) += pm.o
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
new file mode 100644
index 000000000000..29c7bd42e25d
--- /dev/null
+++ b/kernel/irq/irqdomain.c
@@ -0,0 +1,122 @@
1#include <linux/irq.h>
2#include <linux/irqdomain.h>
3#include <linux/module.h>
4#include <linux/mutex.h>
5#include <linux/of.h>
6
7static LIST_HEAD(irq_domain_list);
8static DEFINE_MUTEX(irq_domain_mutex);
9
10/**
11 * irq_domain_add() - Register an irq_domain
12 * @domain: ptr to initialized irq_domain structure
13 *
14 * Registers an irq_domain structure. The irq_domain must at a minimum be
15 * initialized with an ops structure pointer, and either a ->to_irq hook or
16 * a valid irq_base value. Everything else is optional.
17 */
18void irq_domain_add(struct irq_domain *domain)
19{
20 struct irq_data *d;
21 int hwirq;
22
23 /*
24 * This assumes that the irq_domain owner has already allocated
25 * the irq_descs. This block will be removed when support for dynamic
26 * allocation of irq_descs is added to irq_domain.
27 */
28 for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
29 d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
30 if (d || d->domain) {
31 /* things are broken; just report, don't clean up */
32 WARN(1, "error: irq_desc already assigned to a domain");
33 return;
34 }
35 d->domain = domain;
36 d->hwirq = hwirq;
37 }
38
39 mutex_lock(&irq_domain_mutex);
40 list_add(&domain->list, &irq_domain_list);
41 mutex_unlock(&irq_domain_mutex);
42}
43
44/**
45 * irq_domain_del() - Unregister an irq_domain
46 * @domain: ptr to registered irq_domain.
47 */
48void irq_domain_del(struct irq_domain *domain)
49{
50 struct irq_data *d;
51 int hwirq;
52
53 mutex_lock(&irq_domain_mutex);
54 list_del(&domain->list);
55 mutex_unlock(&irq_domain_mutex);
56
57 /* Clear the irq_domain assignments */
58 for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
59 d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
60 d->domain = NULL;
61 }
62}
63
64#if defined(CONFIG_OF_IRQ)
65/**
66 * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
67 *
68 * Used by the device tree interrupt mapping code to translate a device tree
69 * interrupt specifier to a valid linux irq number. Returns either a valid
70 * linux IRQ number or 0.
71 *
72 * When the caller no longer need the irq number returned by this function it
73 * should arrange to call irq_dispose_mapping().
74 */
75unsigned int irq_create_of_mapping(struct device_node *controller,
76 const u32 *intspec, unsigned int intsize)
77{
78 struct irq_domain *domain;
79 unsigned long hwirq;
80 unsigned int irq, type;
81 int rc = -EINVAL;
82
83 /* Find a domain which can translate the irq spec */
84 mutex_lock(&irq_domain_mutex);
85 list_for_each_entry(domain, &irq_domain_list, list) {
86 if (!domain->ops->dt_translate)
87 continue;
88 rc = domain->ops->dt_translate(domain, controller,
89 intspec, intsize, &hwirq, &type);
90 if (rc == 0)
91 break;
92 }
93 mutex_unlock(&irq_domain_mutex);
94
95 if (rc != 0)
96 return 0;
97
98 irq = irq_domain_to_irq(domain, hwirq);
99 if (type != IRQ_TYPE_NONE)
100 irq_set_irq_type(irq, type);
101 pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
102 controller->full_name, (int)hwirq, irq, type);
103 return irq;
104}
105EXPORT_SYMBOL_GPL(irq_create_of_mapping);
106
107/**
108 * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
109 * @irq: linux irq number to be discarded
110 *
111 * Calling this function indicates the caller no longer needs a reference to
112 * the linux irq number returned by a prior call to irq_create_of_mapping().
113 */
114void irq_dispose_mapping(unsigned int irq)
115{
116 /*
117 * nothing yet; will be filled when support for dynamic allocation of
118 * irq_descs is added to irq_domain
119 */
120}
121EXPORT_SYMBOL_GPL(irq_dispose_mapping);
122#endif /* CONFIG_OF_IRQ */