diff options
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/prom.h | 5 | ||||
-rw-r--r-- | arch/arm/kernel/devtree.c | 14 | ||||
-rw-r--r-- | include/linux/irq.h | 6 | ||||
-rw-r--r-- | include/linux/irqdomain.h | 81 | ||||
-rw-r--r-- | include/linux/of_irq.h | 4 | ||||
-rw-r--r-- | kernel/irq/Kconfig | 4 | ||||
-rw-r--r-- | kernel/irq/Makefile | 1 | ||||
-rw-r--r-- | kernel/irq/irqdomain.c | 122 |
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 | ||
19 | static inline void irq_dispose_mapping(unsigned int virq) | ||
20 | { | ||
21 | return; | ||
22 | } | ||
23 | |||
24 | extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys); | 19 | extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys); |
25 | extern void arm_dt_memblock_reserve(void); | 20 | extern 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 | */ | ||
143 | unsigned int irq_create_of_mapping(struct device_node *controller, | ||
144 | const u32 *intspec, unsigned int intsize) | ||
145 | { | ||
146 | return intspec[0]; | ||
147 | } | ||
148 | EXPORT_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 | ||
110 | struct msi_desc; | 110 | struct msi_desc; |
111 | struct 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 | */ |
129 | struct irq_data { | 133 | struct 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 | ||
21 | struct device_node; | ||
22 | struct 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 | */ | ||
32 | struct 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 | */ | ||
55 | struct 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 | */ | ||
71 | static 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 | |||
77 | extern void irq_domain_add(struct irq_domain *domain); | ||
78 | extern 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, | |||
63 | extern unsigned int irq_create_of_mapping(struct device_node *controller, | 63 | extern 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 | ||
67 | extern void irq_dispose_mapping(unsigned int irq); | ||
68 | #endif | ||
66 | extern int of_irq_to_resource(struct device_node *dev, int index, | 69 | extern int of_irq_to_resource(struct device_node *dev, int index, |
67 | struct resource *r); | 70 | struct resource *r); |
68 | extern int of_irq_count(struct device_node *dev); | 71 | extern 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); |
71 | extern struct device_node *of_irq_find_parent(struct device_node *child); | 74 | extern 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 | |||
52 | config GENERIC_IRQ_CHIP | 52 | config GENERIC_IRQ_CHIP |
53 | bool | 53 | bool |
54 | 54 | ||
55 | # Generic irq_domain hw <--> linux irq number translation | ||
56 | config IRQ_DOMAIN | ||
57 | bool | ||
58 | |||
55 | # Support forced irq threading | 59 | # Support forced irq threading |
56 | config IRQ_FORCED_THREADING | 60 | config 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 @@ | |||
2 | obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o | 2 | obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o |
3 | obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o | 3 | obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o |
4 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | 4 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o |
5 | obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o | ||
5 | obj-$(CONFIG_PROC_FS) += proc.o | 6 | obj-$(CONFIG_PROC_FS) += proc.o |
6 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | 7 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o |
7 | obj-$(CONFIG_PM_SLEEP) += pm.o | 8 | obj-$(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 | |||
7 | static LIST_HEAD(irq_domain_list); | ||
8 | static 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 | */ | ||
18 | void 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 | */ | ||
48 | void 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 | */ | ||
75 | unsigned 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 | } | ||
105 | EXPORT_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 | */ | ||
114 | void 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 | } | ||
121 | EXPORT_SYMBOL_GPL(irq_dispose_mapping); | ||
122 | #endif /* CONFIG_OF_IRQ */ | ||