diff options
author | Grant Likely <grant.likely@linaro.org> | 2013-09-15 17:32:39 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2013-10-24 06:43:04 -0400 |
commit | 2361613206e66ce59cc0e08efa8d98ec15b84ed1 (patch) | |
tree | 5e4f5fc33f715202f71770890dcc09ac09a2d851 | |
parent | e6d30ab1e7d1281784672c0fc2ffa385cfb7279e (diff) |
of/irq: Refactor interrupt-map parsing
All the users of of_irq_parse_raw pass in a raw interrupt specifier from
the device tree and expect it to be returned (possibly modified) in an
of_phandle_args structure. However, the primary function of
of_irq_parse_raw() is to check for translations due to the presence of
one or more interrupt-map properties. The actual placing of the data
into an of_phandle_args structure is trivial. If it is refactored to
accept an of_phandle_args structure directly, then it becomes possible
to consume of_phandle_args from other sources. This is important for an
upcoming patch that allows a device to be connected to more than one
interrupt parent. It also simplifies the code a bit.
The biggest complication with this patch is that the old version works
on the interrupt specifiers in __be32 form, but the of_phandle_args
structure is intended to carry it in the cpu-native version. A bit of
churn was required to make this work. In the end it results in tighter
code, so the churn is worth it.
Signed-off-by: Grant Likely <grant.likely@linaro.org>
Acked-by: Tony Lindgren <tony@atomide.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/platforms/fsl_uli1575.c | 6 | ||||
-rw-r--r-- | drivers/of/irq.c | 108 | ||||
-rw-r--r-- | drivers/of/of_pci_irq.c | 7 | ||||
-rw-r--r-- | include/linux/of_irq.h | 5 |
4 files changed, 67 insertions, 59 deletions
diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c index 8904046556ad..b97f6f3d3c5b 100644 --- a/arch/powerpc/platforms/fsl_uli1575.c +++ b/arch/powerpc/platforms/fsl_uli1575.c | |||
@@ -322,7 +322,6 @@ static void hpcd_final_uli5288(struct pci_dev *dev) | |||
322 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | 322 | struct pci_controller *hose = pci_bus_to_host(dev->bus); |
323 | struct device_node *hosenode = hose ? hose->dn : NULL; | 323 | struct device_node *hosenode = hose ? hose->dn : NULL; |
324 | struct of_phandle_args oirq; | 324 | struct of_phandle_args oirq; |
325 | int pin = 2; | ||
326 | u32 laddr[3]; | 325 | u32 laddr[3]; |
327 | 326 | ||
328 | if (!machine_is(mpc86xx_hpcd)) | 327 | if (!machine_is(mpc86xx_hpcd)) |
@@ -331,9 +330,12 @@ static void hpcd_final_uli5288(struct pci_dev *dev) | |||
331 | if (!hosenode) | 330 | if (!hosenode) |
332 | return; | 331 | return; |
333 | 332 | ||
333 | oirq.np = hosenode; | ||
334 | oirq.args[0] = 2; | ||
335 | oirq.args_count = 1; | ||
334 | laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8); | 336 | laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8); |
335 | laddr[1] = laddr[2] = 0; | 337 | laddr[1] = laddr[2] = 0; |
336 | of_irq_parse_raw(hosenode, &pin, 1, laddr, &oirq); | 338 | of_irq_parse_raw(laddr, &oirq); |
337 | dev->irq = irq_create_of_mapping(&oirq); | 339 | dev->irq = irq_create_of_mapping(&oirq); |
338 | } | 340 | } |
339 | 341 | ||
diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 84184c44e8db..0ed5ed4a5f9b 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c | |||
@@ -80,31 +80,32 @@ struct device_node *of_irq_find_parent(struct device_node *child) | |||
80 | /** | 80 | /** |
81 | * of_irq_parse_raw - Low level interrupt tree parsing | 81 | * of_irq_parse_raw - Low level interrupt tree parsing |
82 | * @parent: the device interrupt parent | 82 | * @parent: the device interrupt parent |
83 | * @intspec: interrupt specifier ("interrupts" property of the device) | 83 | * @addr: address specifier (start of "reg" property of the device) in be32 format |
84 | * @ointsize: size of the passed in interrupt specifier | 84 | * @out_irq: structure of_irq updated by this function |
85 | * @addr: address specifier (start of "reg" property of the device) | ||
86 | * @out_irq: structure of_irq filled by this function | ||
87 | * | 85 | * |
88 | * Returns 0 on success and a negative number on error | 86 | * Returns 0 on success and a negative number on error |
89 | * | 87 | * |
90 | * This function is a low-level interrupt tree walking function. It | 88 | * This function is a low-level interrupt tree walking function. It |
91 | * can be used to do a partial walk with synthetized reg and interrupts | 89 | * can be used to do a partial walk with synthetized reg and interrupts |
92 | * properties, for example when resolving PCI interrupts when no device | 90 | * properties, for example when resolving PCI interrupts when no device |
93 | * node exist for the parent. | 91 | * node exist for the parent. It takes an interrupt specifier structure as |
92 | * input, walks the tree looking for any interrupt-map properties, translates | ||
93 | * the specifier for each map, and then returns the translated map. | ||
94 | */ | 94 | */ |
95 | int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | 95 | int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) |
96 | u32 ointsize, const __be32 *addr, struct of_phandle_args *out_irq) | ||
97 | { | 96 | { |
98 | struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; | 97 | struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; |
99 | const __be32 *tmp, *imap, *imask; | 98 | __be32 initial_match_array[8]; |
99 | const __be32 *match_array = initial_match_array; | ||
100 | const __be32 *tmp, *imap, *imask, dummy_imask[] = { ~0, ~0, ~0, ~0, ~0 }; | ||
100 | u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; | 101 | u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; |
101 | int imaplen, match, i; | 102 | int imaplen, match, i; |
102 | 103 | ||
103 | pr_debug("of_irq_parse_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", | 104 | pr_debug("of_irq_parse_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", |
104 | of_node_full_name(parent), be32_to_cpup(intspec), | 105 | of_node_full_name(out_irq->np), out_irq->args[0], out_irq->args[1], |
105 | be32_to_cpup(intspec + 1), ointsize); | 106 | out_irq->args_count); |
106 | 107 | ||
107 | ipar = of_node_get(parent); | 108 | ipar = of_node_get(out_irq->np); |
108 | 109 | ||
109 | /* First get the #interrupt-cells property of the current cursor | 110 | /* First get the #interrupt-cells property of the current cursor |
110 | * that tells us how to interpret the passed-in intspec. If there | 111 | * that tells us how to interpret the passed-in intspec. If there |
@@ -127,7 +128,7 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | |||
127 | 128 | ||
128 | pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize); | 129 | pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize); |
129 | 130 | ||
130 | if (ointsize != intsize) | 131 | if (out_irq->args_count != intsize) |
131 | return -EINVAL; | 132 | return -EINVAL; |
132 | 133 | ||
133 | /* Look for this #address-cells. We have to implement the old linux | 134 | /* Look for this #address-cells. We have to implement the old linux |
@@ -146,6 +147,21 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | |||
146 | 147 | ||
147 | pr_debug(" -> addrsize=%d\n", addrsize); | 148 | pr_debug(" -> addrsize=%d\n", addrsize); |
148 | 149 | ||
150 | /* If we were passed no "reg" property and we attempt to parse | ||
151 | * an interrupt-map, then #address-cells must be 0. | ||
152 | * Fail if it's not. | ||
153 | */ | ||
154 | if (addr == NULL && addrsize != 0) { | ||
155 | pr_debug(" -> no reg passed in when needed !\n"); | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | |||
159 | /* Precalculate the match array - this simplifies match loop */ | ||
160 | for (i = 0; i < addrsize; i++) | ||
161 | initial_match_array[i] = addr[i]; | ||
162 | for (i = 0; i < intsize; i++) | ||
163 | initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]); | ||
164 | |||
149 | /* Now start the actual "proper" walk of the interrupt tree */ | 165 | /* Now start the actual "proper" walk of the interrupt tree */ |
150 | while (ipar != NULL) { | 166 | while (ipar != NULL) { |
151 | /* Now check if cursor is an interrupt-controller and if it is | 167 | /* Now check if cursor is an interrupt-controller and if it is |
@@ -154,11 +170,6 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | |||
154 | if (of_get_property(ipar, "interrupt-controller", NULL) != | 170 | if (of_get_property(ipar, "interrupt-controller", NULL) != |
155 | NULL) { | 171 | NULL) { |
156 | pr_debug(" -> got it !\n"); | 172 | pr_debug(" -> got it !\n"); |
157 | for (i = 0; i < intsize; i++) | ||
158 | out_irq->args[i] = | ||
159 | of_read_number(intspec +i, 1); | ||
160 | out_irq->args_count = intsize; | ||
161 | out_irq->np = ipar; | ||
162 | of_node_put(old); | 173 | of_node_put(old); |
163 | return 0; | 174 | return 0; |
164 | } | 175 | } |
@@ -175,34 +186,16 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | |||
175 | 186 | ||
176 | /* Look for a mask */ | 187 | /* Look for a mask */ |
177 | imask = of_get_property(ipar, "interrupt-map-mask", NULL); | 188 | imask = of_get_property(ipar, "interrupt-map-mask", NULL); |
178 | 189 | if (!imask) | |
179 | /* If we were passed no "reg" property and we attempt to parse | 190 | imask = dummy_imask; |
180 | * an interrupt-map, then #address-cells must be 0. | ||
181 | * Fail if it's not. | ||
182 | */ | ||
183 | if (addr == NULL && addrsize != 0) { | ||
184 | pr_debug(" -> no reg passed in when needed !\n"); | ||
185 | goto fail; | ||
186 | } | ||
187 | 191 | ||
188 | /* Parse interrupt-map */ | 192 | /* Parse interrupt-map */ |
189 | match = 0; | 193 | match = 0; |
190 | while (imaplen > (addrsize + intsize + 1) && !match) { | 194 | while (imaplen > (addrsize + intsize + 1) && !match) { |
191 | /* Compare specifiers */ | 195 | /* Compare specifiers */ |
192 | match = 1; | 196 | match = 1; |
193 | for (i = 0; i < addrsize && match; ++i) { | 197 | for (i = 0; i < (addrsize + intsize); i++, imaplen--) |
194 | __be32 mask = imask ? imask[i] | 198 | match = !((match_array[i] ^ *imap++) & imask[i]); |
195 | : cpu_to_be32(0xffffffffu); | ||
196 | match = ((addr[i] ^ imap[i]) & mask) == 0; | ||
197 | } | ||
198 | for (; i < (addrsize + intsize) && match; ++i) { | ||
199 | __be32 mask = imask ? imask[i] | ||
200 | : cpu_to_be32(0xffffffffu); | ||
201 | match = | ||
202 | ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; | ||
203 | } | ||
204 | imap += addrsize + intsize; | ||
205 | imaplen -= addrsize + intsize; | ||
206 | 199 | ||
207 | pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); | 200 | pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); |
208 | 201 | ||
@@ -247,12 +240,18 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | |||
247 | if (!match) | 240 | if (!match) |
248 | goto fail; | 241 | goto fail; |
249 | 242 | ||
250 | of_node_put(old); | 243 | /* |
251 | old = of_node_get(newpar); | 244 | * Successfully parsed an interrrupt-map translation; copy new |
245 | * interrupt specifier into the out_irq structure | ||
246 | */ | ||
247 | of_node_put(out_irq->np); | ||
248 | out_irq->np = of_node_get(newpar); | ||
249 | |||
250 | match_array = imap - newaddrsize - newintsize; | ||
251 | for (i = 0; i < newintsize; i++) | ||
252 | out_irq->args[i] = be32_to_cpup(imap - newintsize + i); | ||
253 | out_irq->args_count = intsize = newintsize; | ||
252 | addrsize = newaddrsize; | 254 | addrsize = newaddrsize; |
253 | intsize = newintsize; | ||
254 | intspec = imap - intsize; | ||
255 | addr = intspec - addrsize; | ||
256 | 255 | ||
257 | skiplevel: | 256 | skiplevel: |
258 | /* Iterate again with new parent */ | 257 | /* Iterate again with new parent */ |
@@ -263,7 +262,7 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | |||
263 | } | 262 | } |
264 | fail: | 263 | fail: |
265 | of_node_put(ipar); | 264 | of_node_put(ipar); |
266 | of_node_put(old); | 265 | of_node_put(out_irq->np); |
267 | of_node_put(newpar); | 266 | of_node_put(newpar); |
268 | 267 | ||
269 | return -EINVAL; | 268 | return -EINVAL; |
@@ -276,15 +275,16 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw); | |||
276 | * @index: index of the interrupt to resolve | 275 | * @index: index of the interrupt to resolve |
277 | * @out_irq: structure of_irq filled by this function | 276 | * @out_irq: structure of_irq filled by this function |
278 | * | 277 | * |
279 | * This function resolves an interrupt, walking the tree, for a given | 278 | * This function resolves an interrupt for a node by walking the interrupt tree, |
280 | * device-tree node. It's the high level pendant to of_irq_parse_raw(). | 279 | * finding which interrupt controller node it is attached to, and returning the |
280 | * interrupt specifier that can be used to retrieve a Linux IRQ number. | ||
281 | */ | 281 | */ |
282 | int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) | 282 | int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) |
283 | { | 283 | { |
284 | struct device_node *p; | 284 | struct device_node *p; |
285 | const __be32 *intspec, *tmp, *addr; | 285 | const __be32 *intspec, *tmp, *addr; |
286 | u32 intsize, intlen; | 286 | u32 intsize, intlen; |
287 | int res = -EINVAL; | 287 | int i, res = -EINVAL; |
288 | 288 | ||
289 | pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index); | 289 | pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index); |
290 | 290 | ||
@@ -320,9 +320,15 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar | |||
320 | if ((index + 1) * intsize > intlen) | 320 | if ((index + 1) * intsize > intlen) |
321 | goto out; | 321 | goto out; |
322 | 322 | ||
323 | /* Get new specifier and map it */ | 323 | /* Copy intspec into irq structure */ |
324 | res = of_irq_parse_raw(p, intspec + index * intsize, intsize, | 324 | intspec += index * intsize; |
325 | addr, out_irq); | 325 | out_irq->np = p; |
326 | out_irq->args_count = intsize; | ||
327 | for (i = 0; i < intsize; i++) | ||
328 | out_irq->args[i] = be32_to_cpup(intspec++); | ||
329 | |||
330 | /* Check if there are any interrupt-map translations to process */ | ||
331 | res = of_irq_parse_raw(addr, out_irq); | ||
326 | out: | 332 | out: |
327 | of_node_put(p); | 333 | of_node_put(p); |
328 | return res; | 334 | return res; |
diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c index ee3293d4b66b..303afebc247a 100644 --- a/drivers/of/of_pci_irq.c +++ b/drivers/of/of_pci_irq.c | |||
@@ -85,9 +85,12 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq | |||
85 | pdev = ppdev; | 85 | pdev = ppdev; |
86 | } | 86 | } |
87 | 87 | ||
88 | out_irq->np = ppnode; | ||
89 | out_irq->args_count = 1; | ||
90 | out_irq->args[0] = lspec; | ||
88 | lspec_be = cpu_to_be32(lspec); | 91 | lspec_be = cpu_to_be32(lspec); |
89 | laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8)); | 92 | laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8)); |
90 | laddr[1] = laddr[2] = cpu_to_be32(0); | 93 | laddr[1] = laddr[2] = cpu_to_be32(0); |
91 | return of_irq_parse_raw(ppnode, &lspec_be, 1, laddr, out_irq); | 94 | return of_irq_parse_raw(laddr, out_irq); |
92 | } | 95 | } |
93 | EXPORT_SYMBOL_GPL(of_irq_parse_pci); | 96 | EXPORT_SYMBOL_GPL(of_irq_parse_pci); |
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index 3bbba8d6adc8..c0d6dfe80895 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h | |||
@@ -31,10 +31,7 @@ static inline int of_irq_parse_oldworld(struct device_node *device, int index, | |||
31 | } | 31 | } |
32 | #endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */ | 32 | #endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */ |
33 | 33 | ||
34 | 34 | extern int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq); | |
35 | extern int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec, | ||
36 | u32 ointsize, const __be32 *addr, | ||
37 | struct of_phandle_args *out_irq); | ||
38 | extern int of_irq_parse_one(struct device_node *device, int index, | 35 | extern int of_irq_parse_one(struct device_node *device, int index, |
39 | struct of_phandle_args *out_irq); | 36 | struct of_phandle_args *out_irq); |
40 | extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data); | 37 | extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data); |