aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/irqdomain.c
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2012-02-14 16:06:54 -0500
committerGrant Likely <grant.likely@secretlab.ca>2012-02-16 08:11:22 -0500
commita8db8cf0d894df5f1dcfd4bce9894e0dbcc01c96 (patch)
treef9f2c53c57eeb04e5df60671951bcf4f2ca4966e /kernel/irq/irqdomain.c
parent68700650e71b6bb6636673f4f9c8ec807353d8d6 (diff)
irq_domain: Replace irq_alloc_host() with revmap-specific initializers
Each revmap type has different arguments for setting up the revmap. This patch splits up the generator functions so that each revmap type can do its own setup and the user doesn't need to keep track of how each revmap type handles the arguments. This patch also adds a host_data argument to the generators. There are cases where the host_data pointer will be needed before the function returns. ie. the legacy map calls the .map callback for each irq before returning. v2: - Add void *host_data argument to irq_domain_add_*() functions - fixed failure to compile - Moved IRQ_DOMAIN_MAP_* defines into irqdomain.c Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Cc: Rob Herring <rob.herring@calxeda.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Milton Miller <miltonm@bga.com> Tested-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'kernel/irq/irqdomain.c')
-rw-r--r--kernel/irq/irqdomain.c200
1 files changed, 130 insertions, 70 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 432d292b33f8..acedba1a2651 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -13,6 +13,11 @@
13#include <linux/smp.h> 13#include <linux/smp.h>
14#include <linux/fs.h> 14#include <linux/fs.h>
15 15
16#define IRQ_DOMAIN_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */
17#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
18#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
19#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
20
16static LIST_HEAD(irq_domain_list); 21static LIST_HEAD(irq_domain_list);
17static DEFINE_MUTEX(irq_domain_mutex); 22static DEFINE_MUTEX(irq_domain_mutex);
18 23
@@ -27,100 +32,158 @@ static int default_irq_domain_match(struct irq_domain *d, struct device_node *np
27} 32}
28 33
29/** 34/**
30 * irq_alloc_host() - Allocate a new irq_domain data structure 35 * irq_domain_alloc() - Allocate a new irq_domain data structure
31 * @of_node: optional device-tree node of the interrupt controller 36 * @of_node: optional device-tree node of the interrupt controller
32 * @revmap_type: type of reverse mapping to use 37 * @revmap_type: type of reverse mapping to use
33 * @revmap_arg: for IRQ_DOMAIN_MAP_LINEAR linear only: size of the map
34 * @ops: map/unmap domain callbacks 38 * @ops: map/unmap domain callbacks
35 * @inval_irq: provide a hw number in that domain space that is always invalid 39 * @host_data: Controller private data pointer
36 * 40 *
37 * Allocates and initialize and irq_domain structure. Note that in the case of 41 * Allocates and initialize and irq_domain structure. Caller is expected to
38 * IRQ_DOMAIN_MAP_LEGACY, the map() callback will be called before this returns 42 * register allocated irq_domain with irq_domain_register(). Returns pointer
39 * for all legacy interrupts except 0 (which is always the invalid irq for 43 * to IRQ domain, or NULL on failure.
40 * a legacy controller). For a IRQ_DOMAIN_MAP_LINEAR, the map is allocated by
41 * this call as well. For a IRQ_DOMAIN_MAP_TREE, the radix tree will be
42 * allocated later during boot automatically (the reverse mapping will use the
43 * slow path until that happens).
44 */ 44 */
45struct irq_domain *irq_alloc_host(struct device_node *of_node, 45static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
46 unsigned int revmap_type, 46 unsigned int revmap_type,
47 unsigned int revmap_arg, 47 struct irq_domain_ops *ops,
48 struct irq_domain_ops *ops, 48 void *host_data)
49 irq_hw_number_t inval_irq)
50{ 49{
51 struct irq_domain *domain, *h; 50 struct irq_domain *domain;
52 unsigned int size = sizeof(struct irq_domain);
53 unsigned int i;
54 unsigned int *rmap;
55 51
56 /* Allocate structure and revmap table if using linear mapping */ 52 domain = kzalloc(sizeof(*domain), GFP_KERNEL);
57 if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) 53 if (WARN_ON(!domain))
58 size += revmap_arg * sizeof(unsigned int);
59 domain = kzalloc(size, GFP_KERNEL);
60 if (domain == NULL)
61 return NULL; 54 return NULL;
62 55
63 /* Fill structure */ 56 /* Fill structure */
64 domain->revmap_type = revmap_type; 57 domain->revmap_type = revmap_type;
65 domain->inval_irq = inval_irq;
66 domain->ops = ops; 58 domain->ops = ops;
59 domain->host_data = host_data;
67 domain->of_node = of_node_get(of_node); 60 domain->of_node = of_node_get(of_node);
68 61
69 if (domain->ops->match == NULL) 62 if (domain->ops->match == NULL)
70 domain->ops->match = default_irq_domain_match; 63 domain->ops->match = default_irq_domain_match;
71 64
65 return domain;
66}
67
68static void irq_domain_add(struct irq_domain *domain)
69{
70 mutex_lock(&irq_domain_mutex);
71 list_add(&domain->link, &irq_domain_list);
72 mutex_unlock(&irq_domain_mutex);
73 pr_debug("irq: Allocated domain of type %d @0x%p\n",
74 domain->revmap_type, domain);
75}
76
77/**
78 * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
79 * @of_node: pointer to interrupt controller's device tree node.
80 * @ops: map/unmap domain callbacks
81 * @host_data: Controller private data pointer
82 *
83 * Note: the map() callback will be called before this function returns
84 * for all legacy interrupts except 0 (which is always the invalid irq for
85 * a legacy controller).
86 */
87struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
88 struct irq_domain_ops *ops,
89 void *host_data)
90{
91 struct irq_domain *domain, *h;
92 unsigned int i;
93
94 domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data);
95 if (!domain)
96 return NULL;
97
72 mutex_lock(&irq_domain_mutex); 98 mutex_lock(&irq_domain_mutex);
73 /* Make sure only one legacy controller can be created */ 99 /* Make sure only one legacy controller can be created */
74 if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { 100 list_for_each_entry(h, &irq_domain_list, link) {
75 list_for_each_entry(h, &irq_domain_list, link) { 101 if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) {
76 if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { 102 mutex_unlock(&irq_domain_mutex);
77 mutex_unlock(&irq_domain_mutex); 103 of_node_put(domain->of_node);
78 of_node_put(domain->of_node); 104 kfree(domain);
79 kfree(domain); 105 return NULL;
80 return NULL;
81 }
82 } 106 }
83 } 107 }
84 list_add(&domain->link, &irq_domain_list); 108 list_add(&domain->link, &irq_domain_list);
85 mutex_unlock(&irq_domain_mutex); 109 mutex_unlock(&irq_domain_mutex);
86 110
87 /* Additional setups per revmap type */ 111 /* setup us as the domain for all legacy interrupts */
88 switch(revmap_type) { 112 for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
89 case IRQ_DOMAIN_MAP_LEGACY: 113 struct irq_data *irq_data = irq_get_irq_data(i);
90 /* 0 is always the invalid number for legacy */ 114 irq_data->hwirq = i;
91 domain->inval_irq = 0; 115 irq_data->domain = domain;
92 /* setup us as the domain for all legacy interrupts */ 116
93 for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { 117 /* Legacy flags are left to default at this point,
94 struct irq_data *irq_data = irq_get_irq_data(i); 118 * one can then use irq_create_mapping() to
95 irq_data->hwirq = i; 119 * explicitly change them
96 irq_data->domain = domain; 120 */
97 121 ops->map(domain, i, i);
98 /* Legacy flags are left to default at this point, 122
99 * one can then use irq_create_mapping() to 123 /* Clear norequest flags */
100 * explicitly change them 124 irq_clear_status_flags(i, IRQ_NOREQUEST);
101 */
102 ops->map(domain, i, i);
103
104 /* Clear norequest flags */
105 irq_clear_status_flags(i, IRQ_NOREQUEST);
106 }
107 break;
108 case IRQ_DOMAIN_MAP_LINEAR:
109 rmap = (unsigned int *)(domain + 1);
110 for (i = 0; i < revmap_arg; i++)
111 rmap[i] = 0;
112 domain->revmap_data.linear.size = revmap_arg;
113 domain->revmap_data.linear.revmap = rmap;
114 break;
115 case IRQ_DOMAIN_MAP_TREE:
116 INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
117 break;
118 default:
119 break;
120 } 125 }
126 return domain;
127}
121 128
122 pr_debug("irq: Allocated domain of type %d @0x%p\n", revmap_type, domain); 129/**
130 * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
131 * @of_node: pointer to interrupt controller's device tree node.
132 * @ops: map/unmap domain callbacks
133 * @host_data: Controller private data pointer
134 */
135struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
136 unsigned int size,
137 struct irq_domain_ops *ops,
138 void *host_data)
139{
140 struct irq_domain *domain;
141 unsigned int *revmap;
142
143 revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL);
144 if (WARN_ON(!revmap))
145 return NULL;
123 146
147 domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data);
148 if (!domain) {
149 kfree(revmap);
150 return NULL;
151 }
152 domain->revmap_data.linear.size = size;
153 domain->revmap_data.linear.revmap = revmap;
154 irq_domain_add(domain);
155 return domain;
156}
157
158struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
159 struct irq_domain_ops *ops,
160 void *host_data)
161{
162 struct irq_domain *domain = irq_domain_alloc(of_node,
163 IRQ_DOMAIN_MAP_NOMAP, ops, host_data);
164 if (domain)
165 irq_domain_add(domain);
166 return domain;
167}
168
169/**
170 * irq_domain_add_tree()
171 * @of_node: pointer to interrupt controller's device tree node.
172 * @ops: map/unmap domain callbacks
173 *
174 * Note: The radix tree will be allocated later during boot automatically
175 * (the reverse mapping will use the slow path until that happens).
176 */
177struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
178 struct irq_domain_ops *ops,
179 void *host_data)
180{
181 struct irq_domain *domain = irq_domain_alloc(of_node,
182 IRQ_DOMAIN_MAP_TREE, ops, host_data);
183 if (domain) {
184 INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
185 irq_domain_add(domain);
186 }
124 return domain; 187 return domain;
125} 188}
126 189
@@ -393,9 +456,6 @@ void irq_dispose_mapping(unsigned int virq)
393 break; 456 break;
394 } 457 }
395 458
396 /* Destroy map */
397 irq_data->hwirq = domain->inval_irq;
398
399 irq_free_desc(virq); 459 irq_free_desc(virq);
400} 460}
401EXPORT_SYMBOL_GPL(irq_dispose_mapping); 461EXPORT_SYMBOL_GPL(irq_dispose_mapping);