diff options
| author | Grant Likely <grant.likely@linaro.org> | 2013-09-15 17:32:39 -0400 |
|---|---|---|
| committer | Shawn Guo <shawn.guo@freescale.com> | 2014-05-16 04:19:12 -0400 |
| commit | c5754b7462e34a7ac8d990db57b5647fc8783140 (patch) | |
| tree | 850777941159eb41cebcc88f077b9c148f3c0a81 /drivers/of | |
| parent | 568f4b903fe1cfc8464c0ce51ad5882c7e227a0e (diff) | |
ENGR00313685-4 of/irq: Refactor interrupt-map parsing
commit 2361613206e66ce59cc0e08efa8d98ec15b84ed1 upstream.
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>
Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
Conflicts:
drivers/of/irq.c
Diffstat (limited to 'drivers/of')
| -rw-r--r-- | drivers/of/irq.c | 108 | ||||
| -rw-r--r-- | drivers/of/of_pci_irq.c | 7 |
2 files changed, 62 insertions, 53 deletions
diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 231fd5560e0d..5dc08c865122 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 | parent->full_name, 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", ipar->full_name, intsize); | 129 | pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", ipar->full_name, 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", device->full_name, index); | 289 | pr_debug("of_irq_parse_one: dev=%s, index=%d\n", device->full_name, 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); |
