aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-06 15:37:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-06 15:37:04 -0400
commit2cb7b5a38c45b48e9ffb8b382c675a4d64ecccde (patch)
tree03a4960e9e30a023fdd77b558012a2d6a9ac23ab
parentb2c311075db578f1433d9b303698491bfa21279a (diff)
parent798f0fd188be3656991c8745104b5ee045769a5f (diff)
Merge tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux
Pull irqdomain refactoring from Grant Likely: "This is the long awaited simplification of irqdomain. It gets rid of the different types of irq domains and instead both linear and tree mappings can be supported in a single domain. Doing this removes a lot of special case code and makes irq domains simpler to understand overall" * tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux: irq: fix checkpatch error irqdomain: Include hwirq number in /proc/interrupts irqdomain: make irq_linear_revmap() a fast path again irqdomain: remove irq_domain_generate_simple() irqdomain: Refactor irq_domain_associate_many() irqdomain: Beef up debugfs output irqdomain: Clean up aftermath of irq_domain refactoring irqdomain: Eliminate revmap type irqdomain: merge linear and tree reverse mappings. irqdomain: Add a name field irqdomain: Replace LEGACY mapping with LINEAR irqdomain: Relax failure path on setting up mappings
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.c2
-rw-r--r--arch/powerpc/platforms/powermac/smp.c2
-rw-r--r--arch/x86/kernel/devicetree.c4
-rw-r--r--include/linux/irqdomain.h142
-rw-r--r--kernel/irq/generic-chip.c6
-rw-r--r--kernel/irq/irqdomain.c579
-rw-r--r--kernel/irq/proc.c2
7 files changed, 264 insertions, 473 deletions
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 8c6dc42ecf65..9e5dfbcc00af 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -239,7 +239,7 @@ void __init beatic_init_IRQ(void)
239 ppc_md.get_irq = beatic_get_irq; 239 ppc_md.get_irq = beatic_get_irq;
240 240
241 /* Allocate an irq host */ 241 /* Allocate an irq host */
242 beatic_host = irq_domain_add_nomap(NULL, 0, &beatic_pic_host_ops, NULL); 242 beatic_host = irq_domain_add_nomap(NULL, ~0, &beatic_pic_host_ops, NULL);
243 BUG_ON(beatic_host == NULL); 243 BUG_ON(beatic_host == NULL);
244 irq_set_default_host(beatic_host); 244 irq_set_default_host(beatic_host);
245} 245}
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 49c9f9501c21..5cbd4d67d5c4 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -192,7 +192,7 @@ static int psurge_secondary_ipi_init(void)
192{ 192{
193 int rc = -ENOMEM; 193 int rc = -ENOMEM;
194 194
195 psurge_host = irq_domain_add_nomap(NULL, 0, &psurge_host_ops, NULL); 195 psurge_host = irq_domain_add_nomap(NULL, ~0, &psurge_host_ops, NULL);
196 196
197 if (psurge_host) 197 if (psurge_host)
198 psurge_secondary_virq = irq_create_direct_mapping(psurge_host); 198 psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index b1581527a236..4934890e4db2 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -364,9 +364,7 @@ static void dt_add_ioapic_domain(unsigned int ioapic_num,
364 * and assigned so we can keep the 1:1 mapping which the ioapic 364 * and assigned so we can keep the 1:1 mapping which the ioapic
365 * is having. 365 * is having.
366 */ 366 */
367 ret = irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY); 367 irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
368 if (ret)
369 pr_err("Error mapping legacy IRQs: %d\n", ret);
370 368
371 if (num > NR_IRQS_LEGACY) { 369 if (num > NR_IRQS_LEGACY) {
372 ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY, 370 ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY,
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index ba2c708adcff..c983ed18c332 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -73,57 +73,48 @@ struct irq_domain_chip_generic;
73/** 73/**
74 * struct irq_domain - Hardware interrupt number translation object 74 * struct irq_domain - Hardware interrupt number translation object
75 * @link: Element in global irq_domain list. 75 * @link: Element in global irq_domain list.
76 * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This 76 * @name: Name of interrupt domain
77 * will be one of the IRQ_DOMAIN_MAP_* values.
78 * @revmap_data: Revmap method specific data.
79 * @ops: pointer to irq_domain methods 77 * @ops: pointer to irq_domain methods
80 * @host_data: private data pointer for use by owner. Not touched by irq_domain 78 * @host_data: private data pointer for use by owner. Not touched by irq_domain
81 * core code. 79 * core code.
82 * @irq_base: Start of irq_desc range assigned to the irq_domain. The creator 80 *
83 * of the irq_domain is responsible for allocating the array of 81 * Optional elements
84 * irq_desc structures. 82 * @of_node: Pointer to device tree nodes associated with the irq_domain. Used
85 * @nr_irq: Number of irqs managed by the irq domain 83 * when decoding device tree interrupt specifiers.
86 * @hwirq_base: Starting number for hwirqs managed by the irq domain 84 * @gc: Pointer to a list of generic chips. There is a helper function for
87 * @of_node: (optional) Pointer to device tree nodes associated with the 85 * setting up one or more generic chips for interrupt controllers
88 * irq_domain. Used when decoding device tree interrupt specifiers. 86 * drivers using the generic chip library which uses this pointer.
87 *
88 * Revmap data, used internally by irq_domain
89 * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
90 * support direct mapping
91 * @revmap_size: Size of the linear map table @linear_revmap[]
92 * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
93 * @linear_revmap: Linear table of hwirq->virq reverse mappings
89 */ 94 */
90struct irq_domain { 95struct irq_domain {
91 struct list_head link; 96 struct list_head link;
92 97 const char *name;
93 /* type of reverse mapping_technique */
94 unsigned int revmap_type;
95 union {
96 struct {
97 unsigned int size;
98 unsigned int first_irq;
99 irq_hw_number_t first_hwirq;
100 } legacy;
101 struct {
102 unsigned int size;
103 unsigned int *revmap;
104 } linear;
105 struct {
106 unsigned int max_irq;
107 } nomap;
108 struct radix_tree_root tree;
109 } revmap_data;
110 const struct irq_domain_ops *ops; 98 const struct irq_domain_ops *ops;
111 void *host_data; 99 void *host_data;
112 irq_hw_number_t inval_irq;
113 100
114 /* Optional device node pointer */ 101 /* Optional data */
115 struct device_node *of_node; 102 struct device_node *of_node;
116 /* Optional pointer to generic interrupt chips */
117 struct irq_domain_chip_generic *gc; 103 struct irq_domain_chip_generic *gc;
118};
119 104
120#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs. 105 /* reverse map data. The linear map gets appended to the irq_domain */
121 * ie. legacy 8259, gets irqs 1..15 */ 106 irq_hw_number_t hwirq_max;
122#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */ 107 unsigned int revmap_direct_max_irq;
123#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */ 108 unsigned int revmap_size;
124#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */ 109 struct radix_tree_root revmap_tree;
110 unsigned int linear_revmap[];
111};
125 112
126#ifdef CONFIG_IRQ_DOMAIN 113#ifdef CONFIG_IRQ_DOMAIN
114struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
115 irq_hw_number_t hwirq_max, int direct_max,
116 const struct irq_domain_ops *ops,
117 void *host_data);
127struct irq_domain *irq_domain_add_simple(struct device_node *of_node, 118struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
128 unsigned int size, 119 unsigned int size,
129 unsigned int first_irq, 120 unsigned int first_irq,
@@ -135,21 +126,30 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
135 irq_hw_number_t first_hwirq, 126 irq_hw_number_t first_hwirq,
136 const struct irq_domain_ops *ops, 127 const struct irq_domain_ops *ops,
137 void *host_data); 128 void *host_data);
138struct irq_domain *irq_domain_add_linear(struct device_node *of_node, 129extern struct irq_domain *irq_find_host(struct device_node *node);
130extern void irq_set_default_host(struct irq_domain *host);
131
132/**
133 * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain.
134 * @of_node: pointer to interrupt controller's device tree node.
135 * @size: Number of interrupts in the domain.
136 * @ops: map/unmap domain callbacks
137 * @host_data: Controller private data pointer
138 */
139static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
139 unsigned int size, 140 unsigned int size,
140 const struct irq_domain_ops *ops, 141 const struct irq_domain_ops *ops,
141 void *host_data); 142 void *host_data)
142struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, 143{
144 return __irq_domain_add(of_node, size, size, 0, ops, host_data);
145}
146static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
143 unsigned int max_irq, 147 unsigned int max_irq,
144 const struct irq_domain_ops *ops, 148 const struct irq_domain_ops *ops,
145 void *host_data); 149 void *host_data)
146struct irq_domain *irq_domain_add_tree(struct device_node *of_node, 150{
147 const struct irq_domain_ops *ops, 151 return __irq_domain_add(of_node, 0, max_irq, max_irq, ops, host_data);
148 void *host_data); 152}
149
150extern struct irq_domain *irq_find_host(struct device_node *node);
151extern void irq_set_default_host(struct irq_domain *host);
152
153static inline struct irq_domain *irq_domain_add_legacy_isa( 153static inline struct irq_domain *irq_domain_add_legacy_isa(
154 struct device_node *of_node, 154 struct device_node *of_node,
155 const struct irq_domain_ops *ops, 155 const struct irq_domain_ops *ops,
@@ -158,21 +158,40 @@ static inline struct irq_domain *irq_domain_add_legacy_isa(
158 return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, 158 return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
159 host_data); 159 host_data);
160} 160}
161static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
162 const struct irq_domain_ops *ops,
163 void *host_data)
164{
165 return __irq_domain_add(of_node, 0, ~0, 0, ops, host_data);
166}
161 167
162extern void irq_domain_remove(struct irq_domain *host); 168extern void irq_domain_remove(struct irq_domain *host);
163 169
164extern int irq_domain_associate_many(struct irq_domain *domain, 170extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
165 unsigned int irq_base, 171 irq_hw_number_t hwirq);
166 irq_hw_number_t hwirq_base, int count); 172extern void irq_domain_associate_many(struct irq_domain *domain,
167static inline int irq_domain_associate(struct irq_domain *domain, unsigned int irq, 173 unsigned int irq_base,
168 irq_hw_number_t hwirq) 174 irq_hw_number_t hwirq_base, int count);
169{
170 return irq_domain_associate_many(domain, irq, hwirq, 1);
171}
172 175
173extern unsigned int irq_create_mapping(struct irq_domain *host, 176extern unsigned int irq_create_mapping(struct irq_domain *host,
174 irq_hw_number_t hwirq); 177 irq_hw_number_t hwirq);
175extern void irq_dispose_mapping(unsigned int virq); 178extern void irq_dispose_mapping(unsigned int virq);
179
180/**
181 * irq_linear_revmap() - Find a linux irq from a hw irq number.
182 * @domain: domain owning this hardware interrupt
183 * @hwirq: hardware irq number in that domain space
184 *
185 * This is a fast path alternative to irq_find_mapping() that can be
186 * called directly by irq controller code to save a handful of
187 * instructions. It is always safe to call, but won't find irqs mapped
188 * using the radix tree.
189 */
190static inline unsigned int irq_linear_revmap(struct irq_domain *domain,
191 irq_hw_number_t hwirq)
192{
193 return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0;
194}
176extern unsigned int irq_find_mapping(struct irq_domain *host, 195extern unsigned int irq_find_mapping(struct irq_domain *host,
177 irq_hw_number_t hwirq); 196 irq_hw_number_t hwirq);
178extern unsigned int irq_create_direct_mapping(struct irq_domain *host); 197extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
@@ -186,9 +205,6 @@ static inline int irq_create_identity_mapping(struct irq_domain *host,
186 return irq_create_strict_mappings(host, hwirq, hwirq, 1); 205 return irq_create_strict_mappings(host, hwirq, hwirq, 1);
187} 206}
188 207
189extern unsigned int irq_linear_revmap(struct irq_domain *host,
190 irq_hw_number_t hwirq);
191
192extern const struct irq_domain_ops irq_domain_simple_ops; 208extern const struct irq_domain_ops irq_domain_simple_ops;
193 209
194/* stock xlate functions */ 210/* stock xlate functions */
@@ -202,14 +218,6 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
202 const u32 *intspec, unsigned int intsize, 218 const u32 *intspec, unsigned int intsize,
203 irq_hw_number_t *out_hwirq, unsigned int *out_type); 219 irq_hw_number_t *out_hwirq, unsigned int *out_type);
204 220
205#if defined(CONFIG_OF_IRQ)
206extern void irq_domain_generate_simple(const struct of_device_id *match,
207 u64 phys_base, unsigned int irq_start);
208#else /* CONFIG_OF_IRQ */
209static inline void irq_domain_generate_simple(const struct of_device_id *match,
210 u64 phys_base, unsigned int irq_start) { }
211#endif /* !CONFIG_OF_IRQ */
212
213#else /* CONFIG_IRQ_DOMAIN */ 221#else /* CONFIG_IRQ_DOMAIN */
214static inline void irq_dispose_mapping(unsigned int virq) { } 222static inline void irq_dispose_mapping(unsigned int virq) { }
215#endif /* !CONFIG_IRQ_DOMAIN */ 223#endif /* !CONFIG_IRQ_DOMAIN */
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index e3544c19bdd2..10e663ab1f4a 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -275,10 +275,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
275 if (d->gc) 275 if (d->gc)
276 return -EBUSY; 276 return -EBUSY;
277 277
278 if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR) 278 numchips = d->revmap_size / irqs_per_chip;
279 return -EINVAL;
280
281 numchips = d->revmap_data.linear.size / irqs_per_chip;
282 if (!numchips) 279 if (!numchips)
283 return -EINVAL; 280 return -EINVAL;
284 281
@@ -310,6 +307,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
310 /* Calc pointer to the next generic chip */ 307 /* Calc pointer to the next generic chip */
311 tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); 308 tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
312 } 309 }
310 d->name = name;
313 return 0; 311 return 0;
314} 312}
315EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips); 313EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 1ed8dff17eb9..2d7cd3428365 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -23,9 +23,11 @@ static DEFINE_MUTEX(revmap_trees_mutex);
23static struct irq_domain *irq_default_domain; 23static struct irq_domain *irq_default_domain;
24 24
25/** 25/**
26 * irq_domain_alloc() - Allocate a new irq_domain data structure 26 * __irq_domain_add() - Allocate a new irq_domain data structure
27 * @of_node: optional device-tree node of the interrupt controller 27 * @of_node: optional device-tree node of the interrupt controller
28 * @revmap_type: type of reverse mapping to use 28 * @size: Size of linear map; 0 for radix mapping only
29 * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
30 * direct mapping
29 * @ops: map/unmap domain callbacks 31 * @ops: map/unmap domain callbacks
30 * @host_data: Controller private data pointer 32 * @host_data: Controller private data pointer
31 * 33 *
@@ -33,41 +35,35 @@ static struct irq_domain *irq_default_domain;
33 * register allocated irq_domain with irq_domain_register(). Returns pointer 35 * register allocated irq_domain with irq_domain_register(). Returns pointer
34 * to IRQ domain, or NULL on failure. 36 * to IRQ domain, or NULL on failure.
35 */ 37 */
36static struct irq_domain *irq_domain_alloc(struct device_node *of_node, 38struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
37 unsigned int revmap_type, 39 irq_hw_number_t hwirq_max, int direct_max,
38 const struct irq_domain_ops *ops, 40 const struct irq_domain_ops *ops,
39 void *host_data) 41 void *host_data)
40{ 42{
41 struct irq_domain *domain; 43 struct irq_domain *domain;
42 44
43 domain = kzalloc_node(sizeof(*domain), GFP_KERNEL, 45 domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
44 of_node_to_nid(of_node)); 46 GFP_KERNEL, of_node_to_nid(of_node));
45 if (WARN_ON(!domain)) 47 if (WARN_ON(!domain))
46 return NULL; 48 return NULL;
47 49
48 /* Fill structure */ 50 /* Fill structure */
49 domain->revmap_type = revmap_type; 51 INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
50 domain->ops = ops; 52 domain->ops = ops;
51 domain->host_data = host_data; 53 domain->host_data = host_data;
52 domain->of_node = of_node_get(of_node); 54 domain->of_node = of_node_get(of_node);
55 domain->hwirq_max = hwirq_max;
56 domain->revmap_size = size;
57 domain->revmap_direct_max_irq = direct_max;
53 58
54 return domain;
55}
56
57static void irq_domain_free(struct irq_domain *domain)
58{
59 of_node_put(domain->of_node);
60 kfree(domain);
61}
62
63static void irq_domain_add(struct irq_domain *domain)
64{
65 mutex_lock(&irq_domain_mutex); 59 mutex_lock(&irq_domain_mutex);
66 list_add(&domain->link, &irq_domain_list); 60 list_add(&domain->link, &irq_domain_list);
67 mutex_unlock(&irq_domain_mutex); 61 mutex_unlock(&irq_domain_mutex);
68 pr_debug("Allocated domain of type %d @0x%p\n", 62
69 domain->revmap_type, domain); 63 pr_debug("Added domain %s\n", domain->name);
64 return domain;
70} 65}
66EXPORT_SYMBOL_GPL(__irq_domain_add);
71 67
72/** 68/**
73 * irq_domain_remove() - Remove an irq domain. 69 * irq_domain_remove() - Remove an irq domain.
@@ -81,29 +77,12 @@ void irq_domain_remove(struct irq_domain *domain)
81{ 77{
82 mutex_lock(&irq_domain_mutex); 78 mutex_lock(&irq_domain_mutex);
83 79
84 switch (domain->revmap_type) { 80 /*
85 case IRQ_DOMAIN_MAP_LEGACY: 81 * radix_tree_delete() takes care of destroying the root
86 /* 82 * node when all entries are removed. Shout if there are
87 * Legacy domains don't manage their own irq_desc 83 * any mappings left.
88 * allocations, we expect the caller to handle irq_desc 84 */
89 * freeing on their own. 85 WARN_ON(domain->revmap_tree.height);
90 */
91 break;
92 case IRQ_DOMAIN_MAP_TREE:
93 /*
94 * radix_tree_delete() takes care of destroying the root
95 * node when all entries are removed. Shout if there are
96 * any mappings left.
97 */
98 WARN_ON(domain->revmap_data.tree.height);
99 break;
100 case IRQ_DOMAIN_MAP_LINEAR:
101 kfree(domain->revmap_data.linear.revmap);
102 domain->revmap_data.linear.size = 0;
103 break;
104 case IRQ_DOMAIN_MAP_NOMAP:
105 break;
106 }
107 86
108 list_del(&domain->link); 87 list_del(&domain->link);
109 88
@@ -115,44 +94,30 @@ void irq_domain_remove(struct irq_domain *domain)
115 94
116 mutex_unlock(&irq_domain_mutex); 95 mutex_unlock(&irq_domain_mutex);
117 96
118 pr_debug("Removed domain of type %d @0x%p\n", 97 pr_debug("Removed domain %s\n", domain->name);
119 domain->revmap_type, domain);
120 98
121 irq_domain_free(domain); 99 of_node_put(domain->of_node);
100 kfree(domain);
122} 101}
123EXPORT_SYMBOL_GPL(irq_domain_remove); 102EXPORT_SYMBOL_GPL(irq_domain_remove);
124 103
125static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
126 irq_hw_number_t hwirq)
127{
128 irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq;
129 int size = domain->revmap_data.legacy.size;
130
131 if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size))
132 return 0;
133 return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq;
134}
135
136/** 104/**
137 * irq_domain_add_simple() - Allocate and register a simple irq_domain. 105 * irq_domain_add_simple() - Register an irq_domain and optionally map a range of irqs
138 * @of_node: pointer to interrupt controller's device tree node. 106 * @of_node: pointer to interrupt controller's device tree node.
139 * @size: total number of irqs in mapping 107 * @size: total number of irqs in mapping
140 * @first_irq: first number of irq block assigned to the domain, 108 * @first_irq: first number of irq block assigned to the domain,
141 * pass zero to assign irqs on-the-fly. This will result in a 109 * pass zero to assign irqs on-the-fly. If first_irq is non-zero, then
142 * linear IRQ domain so it is important to use irq_create_mapping() 110 * pre-map all of the irqs in the domain to virqs starting at first_irq.
143 * for each used IRQ, especially when SPARSE_IRQ is enabled.
144 * @ops: map/unmap domain callbacks 111 * @ops: map/unmap domain callbacks
145 * @host_data: Controller private data pointer 112 * @host_data: Controller private data pointer
146 * 113 *
147 * Allocates a legacy irq_domain if irq_base is positive or a linear 114 * Allocates an irq_domain, and optionally if first_irq is positive then also
148 * domain otherwise. For the legacy domain, IRQ descriptors will also 115 * allocate irq_descs and map all of the hwirqs to virqs starting at first_irq.
149 * be allocated.
150 * 116 *
151 * This is intended to implement the expected behaviour for most 117 * This is intended to implement the expected behaviour for most
152 * interrupt controllers which is that a linear mapping should 118 * interrupt controllers. If device tree is used, then first_irq will be 0 and
153 * normally be used unless the system requires a legacy mapping in 119 * irqs get mapped dynamically on the fly. However, if the controller requires
154 * order to support supplying interrupt numbers during non-DT 120 * static virq assignments (non-DT boot) then it will set that up correctly.
155 * registration of devices.
156 */ 121 */
157struct irq_domain *irq_domain_add_simple(struct device_node *of_node, 122struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
158 unsigned int size, 123 unsigned int size,
@@ -160,33 +125,25 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
160 const struct irq_domain_ops *ops, 125 const struct irq_domain_ops *ops,
161 void *host_data) 126 void *host_data)
162{ 127{
163 if (first_irq > 0) { 128 struct irq_domain *domain;
164 int irq_base; 129
130 domain = __irq_domain_add(of_node, size, size, 0, ops, host_data);
131 if (!domain)
132 return NULL;
165 133
134 if (first_irq > 0) {
166 if (IS_ENABLED(CONFIG_SPARSE_IRQ)) { 135 if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
167 /* 136 /* attempt to allocated irq_descs */
168 * Set the descriptor allocator to search for a 137 int rc = irq_alloc_descs(first_irq, first_irq, size,
169 * 1-to-1 mapping, such as irq_alloc_desc_at(). 138 of_node_to_nid(of_node));
170 * Use of_node_to_nid() which is defined to 139 if (rc < 0)
171 * numa_node_id() on platforms that have no custom
172 * implementation.
173 */
174 irq_base = irq_alloc_descs(first_irq, first_irq, size,
175 of_node_to_nid(of_node));
176 if (irq_base < 0) {
177 pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", 140 pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
178 first_irq); 141 first_irq);
179 irq_base = first_irq; 142 }
180 } 143 irq_domain_associate_many(domain, first_irq, 0, size);
181 } else
182 irq_base = first_irq;
183
184 return irq_domain_add_legacy(of_node, size, irq_base, 0,
185 ops, host_data);
186 } 144 }
187 145
188 /* A linear domain is the default */ 146 return domain;
189 return irq_domain_add_linear(of_node, size, ops, host_data);
190} 147}
191EXPORT_SYMBOL_GPL(irq_domain_add_simple); 148EXPORT_SYMBOL_GPL(irq_domain_add_simple);
192 149
@@ -213,131 +170,19 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
213 void *host_data) 170 void *host_data)
214{ 171{
215 struct irq_domain *domain; 172 struct irq_domain *domain;
216 unsigned int i;
217 173
218 domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data); 174 domain = __irq_domain_add(of_node, first_hwirq + size,
175 first_hwirq + size, 0, ops, host_data);
219 if (!domain) 176 if (!domain)
220 return NULL; 177 return NULL;
221 178
222 domain->revmap_data.legacy.first_irq = first_irq; 179 irq_domain_associate_many(domain, first_irq, first_hwirq, size);
223 domain->revmap_data.legacy.first_hwirq = first_hwirq;
224 domain->revmap_data.legacy.size = size;
225 180
226 mutex_lock(&irq_domain_mutex);
227 /* Verify that all the irqs are available */
228 for (i = 0; i < size; i++) {
229 int irq = first_irq + i;
230 struct irq_data *irq_data = irq_get_irq_data(irq);
231
232 if (WARN_ON(!irq_data || irq_data->domain)) {
233 mutex_unlock(&irq_domain_mutex);
234 irq_domain_free(domain);
235 return NULL;
236 }
237 }
238
239 /* Claim all of the irqs before registering a legacy domain */
240 for (i = 0; i < size; i++) {
241 struct irq_data *irq_data = irq_get_irq_data(first_irq + i);
242 irq_data->hwirq = first_hwirq + i;
243 irq_data->domain = domain;
244 }
245 mutex_unlock(&irq_domain_mutex);
246
247 for (i = 0; i < size; i++) {
248 int irq = first_irq + i;
249 int hwirq = first_hwirq + i;
250
251 /* IRQ0 gets ignored */
252 if (!irq)
253 continue;
254
255 /* Legacy flags are left to default at this point,
256 * one can then use irq_create_mapping() to
257 * explicitly change them
258 */
259 if (ops->map)
260 ops->map(domain, irq, hwirq);
261
262 /* Clear norequest flags */
263 irq_clear_status_flags(irq, IRQ_NOREQUEST);
264 }
265
266 irq_domain_add(domain);
267 return domain; 181 return domain;
268} 182}
269EXPORT_SYMBOL_GPL(irq_domain_add_legacy); 183EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
270 184
271/** 185/**
272 * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain.
273 * @of_node: pointer to interrupt controller's device tree node.
274 * @size: Number of interrupts in the domain.
275 * @ops: map/unmap domain callbacks
276 * @host_data: Controller private data pointer
277 */
278struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
279 unsigned int size,
280 const struct irq_domain_ops *ops,
281 void *host_data)
282{
283 struct irq_domain *domain;
284 unsigned int *revmap;
285
286 revmap = kzalloc_node(sizeof(*revmap) * size, GFP_KERNEL,
287 of_node_to_nid(of_node));
288 if (WARN_ON(!revmap))
289 return NULL;
290
291 domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data);
292 if (!domain) {
293 kfree(revmap);
294 return NULL;
295 }
296 domain->revmap_data.linear.size = size;
297 domain->revmap_data.linear.revmap = revmap;
298 irq_domain_add(domain);
299 return domain;
300}
301EXPORT_SYMBOL_GPL(irq_domain_add_linear);
302
303struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
304 unsigned int max_irq,
305 const struct irq_domain_ops *ops,
306 void *host_data)
307{
308 struct irq_domain *domain = irq_domain_alloc(of_node,
309 IRQ_DOMAIN_MAP_NOMAP, ops, host_data);
310 if (domain) {
311 domain->revmap_data.nomap.max_irq = max_irq ? max_irq : ~0;
312 irq_domain_add(domain);
313 }
314 return domain;
315}
316EXPORT_SYMBOL_GPL(irq_domain_add_nomap);
317
318/**
319 * irq_domain_add_tree()
320 * @of_node: pointer to interrupt controller's device tree node.
321 * @ops: map/unmap domain callbacks
322 *
323 * Note: The radix tree will be allocated later during boot automatically
324 * (the reverse mapping will use the slow path until that happens).
325 */
326struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
327 const struct irq_domain_ops *ops,
328 void *host_data)
329{
330 struct irq_domain *domain = irq_domain_alloc(of_node,
331 IRQ_DOMAIN_MAP_TREE, ops, host_data);
332 if (domain) {
333 INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
334 irq_domain_add(domain);
335 }
336 return domain;
337}
338EXPORT_SYMBOL_GPL(irq_domain_add_tree);
339
340/**
341 * irq_find_host() - Locates a domain for a given device node 186 * irq_find_host() - Locates a domain for a given device node
342 * @node: device-tree node of the interrupt controller 187 * @node: device-tree node of the interrupt controller
343 */ 188 */
@@ -385,125 +230,108 @@ void irq_set_default_host(struct irq_domain *domain)
385} 230}
386EXPORT_SYMBOL_GPL(irq_set_default_host); 231EXPORT_SYMBOL_GPL(irq_set_default_host);
387 232
388static void irq_domain_disassociate_many(struct irq_domain *domain, 233static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
389 unsigned int irq_base, int count)
390{ 234{
391 /* 235 struct irq_data *irq_data = irq_get_irq_data(irq);
392 * disassociate in reverse order; 236 irq_hw_number_t hwirq;
393 * not strictly necessary, but nice for unwinding
394 */
395 while (count--) {
396 int irq = irq_base + count;
397 struct irq_data *irq_data = irq_get_irq_data(irq);
398 irq_hw_number_t hwirq;
399 237
400 if (WARN_ON(!irq_data || irq_data->domain != domain)) 238 if (WARN(!irq_data || irq_data->domain != domain,
401 continue; 239 "virq%i doesn't exist; cannot disassociate\n", irq))
240 return;
402 241
403 hwirq = irq_data->hwirq; 242 hwirq = irq_data->hwirq;
404 irq_set_status_flags(irq, IRQ_NOREQUEST); 243 irq_set_status_flags(irq, IRQ_NOREQUEST);
405 244
406 /* remove chip and handler */ 245 /* remove chip and handler */
407 irq_set_chip_and_handler(irq, NULL, NULL); 246 irq_set_chip_and_handler(irq, NULL, NULL);
408 247
409 /* Make sure it's completed */ 248 /* Make sure it's completed */
410 synchronize_irq(irq); 249 synchronize_irq(irq);
411 250
412 /* Tell the PIC about it */ 251 /* Tell the PIC about it */
413 if (domain->ops->unmap) 252 if (domain->ops->unmap)
414 domain->ops->unmap(domain, irq); 253 domain->ops->unmap(domain, irq);
415 smp_mb(); 254 smp_mb();
416 255
417 irq_data->domain = NULL; 256 irq_data->domain = NULL;
418 irq_data->hwirq = 0; 257 irq_data->hwirq = 0;
419 258
420 /* Clear reverse map */ 259 /* Clear reverse map for this hwirq */
421 switch(domain->revmap_type) { 260 if (hwirq < domain->revmap_size) {
422 case IRQ_DOMAIN_MAP_LINEAR: 261 domain->linear_revmap[hwirq] = 0;
423 if (hwirq < domain->revmap_data.linear.size) 262 } else {
424 domain->revmap_data.linear.revmap[hwirq] = 0; 263 mutex_lock(&revmap_trees_mutex);
425 break; 264 radix_tree_delete(&domain->revmap_tree, hwirq);
426 case IRQ_DOMAIN_MAP_TREE: 265 mutex_unlock(&revmap_trees_mutex);
427 mutex_lock(&revmap_trees_mutex);
428 radix_tree_delete(&domain->revmap_data.tree, hwirq);
429 mutex_unlock(&revmap_trees_mutex);
430 break;
431 }
432 } 266 }
433} 267}
434 268
435int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, 269int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
436 irq_hw_number_t hwirq_base, int count) 270 irq_hw_number_t hwirq)
437{ 271{
438 unsigned int virq = irq_base; 272 struct irq_data *irq_data = irq_get_irq_data(virq);
439 irq_hw_number_t hwirq = hwirq_base; 273 int ret;
440 int i, ret;
441 274
442 pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__, 275 if (WARN(hwirq >= domain->hwirq_max,
443 of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count); 276 "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name))
277 return -EINVAL;
278 if (WARN(!irq_data, "error: virq%i is not allocated", virq))
279 return -EINVAL;
280 if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
281 return -EINVAL;
444 282
445 for (i = 0; i < count; i++) { 283 mutex_lock(&irq_domain_mutex);
446 struct irq_data *irq_data = irq_get_irq_data(virq + i); 284 irq_data->hwirq = hwirq;
447 285 irq_data->domain = domain;
448 if (WARN(!irq_data, "error: irq_desc not allocated; " 286 if (domain->ops->map) {
449 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i)) 287 ret = domain->ops->map(domain, virq, hwirq);
450 return -EINVAL; 288 if (ret != 0) {
451 if (WARN(irq_data->domain, "error: irq_desc already associated; " 289 /*
452 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i)) 290 * If map() returns -EPERM, this interrupt is protected
453 return -EINVAL; 291 * by the firmware or some other service and shall not
454 }; 292 * be mapped. Don't bother telling the user about it.
455 293 */
456 for (i = 0; i < count; i++, virq++, hwirq++) { 294 if (ret != -EPERM) {
457 struct irq_data *irq_data = irq_get_irq_data(virq); 295 pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
458 296 domain->name, hwirq, virq, ret);
459 irq_data->hwirq = hwirq;
460 irq_data->domain = domain;
461 if (domain->ops->map) {
462 ret = domain->ops->map(domain, virq, hwirq);
463 if (ret != 0) {
464 /*
465 * If map() returns -EPERM, this interrupt is protected
466 * by the firmware or some other service and shall not
467 * be mapped.
468 *
469 * Since on some platforms we blindly try to map everything
470 * we end up with a log full of backtraces.
471 *
472 * So instead, we silently fail on -EPERM, it is the
473 * responsibility of the PIC driver to display a relevant
474 * message if needed.
475 */
476 if (ret != -EPERM) {
477 pr_err("irq-%i==>hwirq-0x%lx mapping failed: %d\n",
478 virq, hwirq, ret);
479 WARN_ON(1);
480 }
481 irq_data->domain = NULL;
482 irq_data->hwirq = 0;
483 goto err_unmap;
484 } 297 }
298 irq_data->domain = NULL;
299 irq_data->hwirq = 0;
300 mutex_unlock(&irq_domain_mutex);
301 return ret;
485 } 302 }
486 303
487 switch (domain->revmap_type) { 304 /* If not already assigned, give the domain the chip's name */
488 case IRQ_DOMAIN_MAP_LINEAR: 305 if (!domain->name && irq_data->chip)
489 if (hwirq < domain->revmap_data.linear.size) 306 domain->name = irq_data->chip->name;
490 domain->revmap_data.linear.revmap[hwirq] = virq; 307 }
491 break;
492 case IRQ_DOMAIN_MAP_TREE:
493 mutex_lock(&revmap_trees_mutex);
494 radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data);
495 mutex_unlock(&revmap_trees_mutex);
496 break;
497 }
498 308
499 irq_clear_status_flags(virq, IRQ_NOREQUEST); 309 if (hwirq < domain->revmap_size) {
310 domain->linear_revmap[hwirq] = virq;
311 } else {
312 mutex_lock(&revmap_trees_mutex);
313 radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
314 mutex_unlock(&revmap_trees_mutex);
500 } 315 }
316 mutex_unlock(&irq_domain_mutex);
317
318 irq_clear_status_flags(virq, IRQ_NOREQUEST);
501 319
502 return 0; 320 return 0;
321}
322EXPORT_SYMBOL_GPL(irq_domain_associate);
503 323
504 err_unmap: 324void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
505 irq_domain_disassociate_many(domain, irq_base, i); 325 irq_hw_number_t hwirq_base, int count)
506 return -EINVAL; 326{
327 int i;
328
329 pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
330 of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
331
332 for (i = 0; i < count; i++) {
333 irq_domain_associate(domain, irq_base + i, hwirq_base + i);
334 }
507} 335}
508EXPORT_SYMBOL_GPL(irq_domain_associate_many); 336EXPORT_SYMBOL_GPL(irq_domain_associate_many);
509 337
@@ -513,7 +341,9 @@ EXPORT_SYMBOL_GPL(irq_domain_associate_many);
513 * 341 *
514 * This routine is used for irq controllers which can choose the hardware 342 * This routine is used for irq controllers which can choose the hardware
515 * interrupt numbers they generate. In such a case it's simplest to use 343 * interrupt numbers they generate. In such a case it's simplest to use
516 * the linux irq as the hardware interrupt number. 344 * the linux irq as the hardware interrupt number. It still uses the linear
345 * or radix tree to store the mapping, but the irq controller can optimize
346 * the revmap path by using the hwirq directly.
517 */ 347 */
518unsigned int irq_create_direct_mapping(struct irq_domain *domain) 348unsigned int irq_create_direct_mapping(struct irq_domain *domain)
519{ 349{
@@ -522,17 +352,14 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
522 if (domain == NULL) 352 if (domain == NULL)
523 domain = irq_default_domain; 353 domain = irq_default_domain;
524 354
525 if (WARN_ON(!domain || domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP))
526 return 0;
527
528 virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node)); 355 virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
529 if (!virq) { 356 if (!virq) {
530 pr_debug("create_direct virq allocation failed\n"); 357 pr_debug("create_direct virq allocation failed\n");
531 return 0; 358 return 0;
532 } 359 }
533 if (virq >= domain->revmap_data.nomap.max_irq) { 360 if (virq >= domain->revmap_direct_max_irq) {
534 pr_err("ERROR: no free irqs available below %i maximum\n", 361 pr_err("ERROR: no free irqs available below %i maximum\n",
535 domain->revmap_data.nomap.max_irq); 362 domain->revmap_direct_max_irq);
536 irq_free_desc(virq); 363 irq_free_desc(virq);
537 return 0; 364 return 0;
538 } 365 }
@@ -569,9 +396,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
569 if (domain == NULL) 396 if (domain == NULL)
570 domain = irq_default_domain; 397 domain = irq_default_domain;
571 if (domain == NULL) { 398 if (domain == NULL) {
572 pr_warning("irq_create_mapping called for" 399 WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
573 " NULL domain, hwirq=%lx\n", hwirq);
574 WARN_ON(1);
575 return 0; 400 return 0;
576 } 401 }
577 pr_debug("-> using domain @%p\n", domain); 402 pr_debug("-> using domain @%p\n", domain);
@@ -583,10 +408,6 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
583 return virq; 408 return virq;
584 } 409 }
585 410
586 /* Get a virtual interrupt number */
587 if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
588 return irq_domain_legacy_revmap(domain, hwirq);
589
590 /* Allocate a virtual interrupt number */ 411 /* Allocate a virtual interrupt number */
591 hint = hwirq % nr_irqs; 412 hint = hwirq % nr_irqs;
592 if (hint == 0) 413 if (hint == 0)
@@ -639,12 +460,7 @@ int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
639 if (unlikely(ret < 0)) 460 if (unlikely(ret < 0))
640 return ret; 461 return ret;
641 462
642 ret = irq_domain_associate_many(domain, irq_base, hwirq_base, count); 463 irq_domain_associate_many(domain, irq_base, hwirq_base, count);
643 if (unlikely(ret < 0)) {
644 irq_free_descs(irq_base, count);
645 return ret;
646 }
647
648 return 0; 464 return 0;
649} 465}
650EXPORT_SYMBOL_GPL(irq_create_strict_mappings); 466EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
@@ -671,8 +487,8 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
671 if (intsize > 0) 487 if (intsize > 0)
672 return intspec[0]; 488 return intspec[0];
673#endif 489#endif
674 pr_warning("no irq domain found for %s !\n", 490 pr_warn("no irq domain found for %s !\n",
675 of_node_full_name(controller)); 491 of_node_full_name(controller));
676 return 0; 492 return 0;
677 } 493 }
678 494
@@ -714,11 +530,7 @@ void irq_dispose_mapping(unsigned int virq)
714 if (WARN_ON(domain == NULL)) 530 if (WARN_ON(domain == NULL))
715 return; 531 return;
716 532
717 /* Never unmap legacy interrupts */ 533 irq_domain_disassociate(domain, virq);
718 if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
719 return;
720
721 irq_domain_disassociate_many(domain, virq, 1);
722 irq_free_desc(virq); 534 irq_free_desc(virq);
723} 535}
724EXPORT_SYMBOL_GPL(irq_dispose_mapping); 536EXPORT_SYMBOL_GPL(irq_dispose_mapping);
@@ -739,63 +551,51 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
739 if (domain == NULL) 551 if (domain == NULL)
740 return 0; 552 return 0;
741 553
742 switch (domain->revmap_type) { 554 if (hwirq < domain->revmap_direct_max_irq) {
743 case IRQ_DOMAIN_MAP_LEGACY:
744 return irq_domain_legacy_revmap(domain, hwirq);
745 case IRQ_DOMAIN_MAP_LINEAR:
746 return irq_linear_revmap(domain, hwirq);
747 case IRQ_DOMAIN_MAP_TREE:
748 rcu_read_lock();
749 data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
750 rcu_read_unlock();
751 if (data)
752 return data->irq;
753 break;
754 case IRQ_DOMAIN_MAP_NOMAP:
755 data = irq_get_irq_data(hwirq); 555 data = irq_get_irq_data(hwirq);
756 if (data && (data->domain == domain) && (data->hwirq == hwirq)) 556 if (data && (data->domain == domain) && (data->hwirq == hwirq))
757 return hwirq; 557 return hwirq;
758 break;
759 } 558 }
760 559
761 return 0; 560 /* Check if the hwirq is in the linear revmap. */
762} 561 if (hwirq < domain->revmap_size)
763EXPORT_SYMBOL_GPL(irq_find_mapping); 562 return domain->linear_revmap[hwirq];
764 563
765/** 564 rcu_read_lock();
766 * irq_linear_revmap() - Find a linux irq from a hw irq number. 565 data = radix_tree_lookup(&domain->revmap_tree, hwirq);
767 * @domain: domain owning this hardware interrupt 566 rcu_read_unlock();
768 * @hwirq: hardware irq number in that domain space 567 return data ? data->irq : 0;
769 *
770 * This is a fast path that can be called directly by irq controller code to
771 * save a handful of instructions.
772 */
773unsigned int irq_linear_revmap(struct irq_domain *domain,
774 irq_hw_number_t hwirq)
775{
776 BUG_ON(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR);
777
778 /* Check revmap bounds; complain if exceeded */
779 if (WARN_ON(hwirq >= domain->revmap_data.linear.size))
780 return 0;
781
782 return domain->revmap_data.linear.revmap[hwirq];
783} 568}
784EXPORT_SYMBOL_GPL(irq_linear_revmap); 569EXPORT_SYMBOL_GPL(irq_find_mapping);
785 570
786#ifdef CONFIG_IRQ_DOMAIN_DEBUG 571#ifdef CONFIG_IRQ_DOMAIN_DEBUG
787static int virq_debug_show(struct seq_file *m, void *private) 572static int virq_debug_show(struct seq_file *m, void *private)
788{ 573{
789 unsigned long flags; 574 unsigned long flags;
790 struct irq_desc *desc; 575 struct irq_desc *desc;
791 const char *p; 576 struct irq_domain *domain;
792 static const char none[] = "none"; 577 struct radix_tree_iter iter;
793 void *data; 578 void *data, **slot;
794 int i; 579 int i;
795 580
796 seq_printf(m, "%-5s %-7s %-15s %-*s %s\n", "irq", "hwirq", 581 seq_printf(m, " %-16s %-6s %-10s %-10s %s\n",
582 "name", "mapped", "linear-max", "direct-max", "devtree-node");
583 mutex_lock(&irq_domain_mutex);
584 list_for_each_entry(domain, &irq_domain_list, link) {
585 int count = 0;
586 radix_tree_for_each_slot(slot, &domain->revmap_tree, &iter, 0)
587 count++;
588 seq_printf(m, "%c%-16s %6u %10u %10u %s\n",
589 domain == irq_default_domain ? '*' : ' ', domain->name,
590 domain->revmap_size + count, domain->revmap_size,
591 domain->revmap_direct_max_irq,
592 domain->of_node ? of_node_full_name(domain->of_node) : "");
593 }
594 mutex_unlock(&irq_domain_mutex);
595
596 seq_printf(m, "%-5s %-7s %-15s %-*s %6s %-14s %s\n", "irq", "hwirq",
797 "chip name", (int)(2 * sizeof(void *) + 2), "chip data", 597 "chip name", (int)(2 * sizeof(void *) + 2), "chip data",
798 "domain name"); 598 "active", "type", "domain");
799 599
800 for (i = 1; i < nr_irqs; i++) { 600 for (i = 1; i < nr_irqs; i++) {
801 desc = irq_to_desc(i); 601 desc = irq_to_desc(i);
@@ -803,28 +603,28 @@ static int virq_debug_show(struct seq_file *m, void *private)
803 continue; 603 continue;
804 604
805 raw_spin_lock_irqsave(&desc->lock, flags); 605 raw_spin_lock_irqsave(&desc->lock, flags);
606 domain = desc->irq_data.domain;
806 607
807 if (desc->action && desc->action->handler) { 608 if (domain) {
808 struct irq_chip *chip; 609 struct irq_chip *chip;
610 int hwirq = desc->irq_data.hwirq;
611 bool direct;
809 612
810 seq_printf(m, "%5d ", i); 613 seq_printf(m, "%5d ", i);
811 seq_printf(m, "0x%05lx ", desc->irq_data.hwirq); 614 seq_printf(m, "0x%05x ", hwirq);
812 615
813 chip = irq_desc_get_chip(desc); 616 chip = irq_desc_get_chip(desc);
814 if (chip && chip->name) 617 seq_printf(m, "%-15s ", (chip && chip->name) ? chip->name : "none");
815 p = chip->name;
816 else
817 p = none;
818 seq_printf(m, "%-15s ", p);
819 618
820 data = irq_desc_get_chip_data(desc); 619 data = irq_desc_get_chip_data(desc);
821 seq_printf(m, data ? "0x%p " : " %p ", data); 620 seq_printf(m, data ? "0x%p " : " %p ", data);
822 621
823 if (desc->irq_data.domain) 622 seq_printf(m, " %c ", (desc->action && desc->action->handler) ? '*' : ' ');
824 p = of_node_full_name(desc->irq_data.domain->of_node); 623 direct = (i == hwirq) && (i < domain->revmap_direct_max_irq);
825 else 624 seq_printf(m, "%6s%-8s ",
826 p = none; 625 (hwirq < domain->revmap_size) ? "LINEAR" : "RADIX",
827 seq_printf(m, "%s\n", p); 626 direct ? "(DIRECT)" : "");
627 seq_printf(m, "%s\n", desc->irq_data.domain->name);
828 } 628 }
829 629
830 raw_spin_unlock_irqrestore(&desc->lock, flags); 630 raw_spin_unlock_irqrestore(&desc->lock, flags);
@@ -921,18 +721,3 @@ const struct irq_domain_ops irq_domain_simple_ops = {
921 .xlate = irq_domain_xlate_onetwocell, 721 .xlate = irq_domain_xlate_onetwocell,
922}; 722};
923EXPORT_SYMBOL_GPL(irq_domain_simple_ops); 723EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
924
925#ifdef CONFIG_OF_IRQ
926void irq_domain_generate_simple(const struct of_device_id *match,
927 u64 phys_base, unsigned int irq_start)
928{
929 struct device_node *node;
930 pr_debug("looking for phys_base=%llx, irq_start=%i\n",
931 (unsigned long long) phys_base, (int) irq_start);
932 node = of_find_matching_node_by_address(NULL, match, phys_base);
933 if (node)
934 irq_domain_add_legacy(node, 32, irq_start, 0,
935 &irq_domain_simple_ops, NULL);
936}
937EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
938#endif
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 19ed5c425c3b..36f6ee181b0c 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -462,6 +462,8 @@ int show_interrupts(struct seq_file *p, void *v)
462 } else { 462 } else {
463 seq_printf(p, " %8s", "None"); 463 seq_printf(p, " %8s", "None");
464 } 464 }
465 if (desc->irq_data.domain)
466 seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq);
465#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL 467#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
466 seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); 468 seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
467#endif 469#endif