Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+67 -59
+4 -2
arch/powerpc/platforms/fsl_uli1575.c
··· 322 322 struct pci_controller *hose = pci_bus_to_host(dev->bus); 323 323 struct device_node *hosenode = hose ? hose->dn : NULL; 324 324 struct of_phandle_args oirq; 325 - int pin = 2; 326 325 u32 laddr[3]; 327 326 328 327 if (!machine_is(mpc86xx_hpcd)) ··· 330 331 if (!hosenode) 331 332 return; 332 333 334 + oirq.np = hosenode; 335 + oirq.args[0] = 2; 336 + oirq.args_count = 1; 333 337 laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8); 334 338 laddr[1] = laddr[2] = 0; 335 - of_irq_parse_raw(hosenode, &pin, 1, laddr, &oirq); 339 + of_irq_parse_raw(laddr, &oirq); 336 340 dev->irq = irq_create_of_mapping(&oirq); 337 341 } 338 342
+57 -51
drivers/of/irq.c
··· 80 80 /** 81 81 * of_irq_parse_raw - Low level interrupt tree parsing 82 82 * @parent: the device interrupt parent 83 - * @intspec: interrupt specifier ("interrupts" property of the device) 84 - * @ointsize: size of the passed in interrupt specifier 85 - * @addr: address specifier (start of "reg" property of the device) 86 - * @out_irq: structure of_irq filled by this function 83 + * @addr: address specifier (start of "reg" property of the device) in be32 format 84 + * @out_irq: structure of_irq updated by this function 87 85 * 88 86 * Returns 0 on success and a negative number on error 89 87 * 90 88 * This function is a low-level interrupt tree walking function. It 91 89 * can be used to do a partial walk with synthetized reg and interrupts 92 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, 96 - u32 ointsize, const __be32 *addr, struct of_phandle_args *out_irq) 95 + int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) 97 96 { 98 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 101 u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; 101 102 int imaplen, match, i; 102 103 103 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 - be32_to_cpup(intspec + 1), ointsize); 105 + of_node_full_name(out_irq->np), out_irq->args[0], out_irq->args[1], 106 + out_irq->args_count); 106 107 107 - ipar = of_node_get(parent); 108 + ipar = of_node_get(out_irq->np); 108 109 109 110 /* First get the #interrupt-cells property of the current cursor 110 111 * that tells us how to interpret the passed-in intspec. If there ··· 128 127 129 128 pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize); 130 129 131 - if (ointsize != intsize) 130 + if (out_irq->args_count != intsize) 132 131 return -EINVAL; 133 132 134 133 /* Look for this #address-cells. We have to implement the old linux ··· 147 146 148 147 pr_debug(" -> addrsize=%d\n", addrsize); 149 148 149 + /* If we were passed no "reg" property and we attempt to parse 150 + * an interrupt-map, then #address-cells must be 0. 151 + * Fail if it's not. 152 + */ 153 + if (addr == NULL && addrsize != 0) { 154 + pr_debug(" -> no reg passed in when needed !\n"); 155 + return -EINVAL; 156 + } 157 + 158 + /* Precalculate the match array - this simplifies match loop */ 159 + for (i = 0; i < addrsize; i++) 160 + initial_match_array[i] = addr[i]; 161 + for (i = 0; i < intsize; i++) 162 + initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]); 163 + 150 164 /* Now start the actual "proper" walk of the interrupt tree */ 151 165 while (ipar != NULL) { 152 166 /* Now check if cursor is an interrupt-controller and if it is ··· 170 154 if (of_get_property(ipar, "interrupt-controller", NULL) != 171 155 NULL) { 172 156 pr_debug(" -> got it !\n"); 173 - for (i = 0; i < intsize; i++) 174 - out_irq->args[i] = 175 - of_read_number(intspec +i, 1); 176 - out_irq->args_count = intsize; 177 - out_irq->np = ipar; 178 157 of_node_put(old); 179 158 return 0; 180 159 } ··· 186 175 187 176 /* Look for a mask */ 188 177 imask = of_get_property(ipar, "interrupt-map-mask", NULL); 189 - 190 - /* If we were passed no "reg" property and we attempt to parse 191 - * an interrupt-map, then #address-cells must be 0. 192 - * Fail if it's not. 193 - */ 194 - if (addr == NULL && addrsize != 0) { 195 - pr_debug(" -> no reg passed in when needed !\n"); 196 - goto fail; 197 - } 178 + if (!imask) 179 + imask = dummy_imask; 198 180 199 181 /* Parse interrupt-map */ 200 182 match = 0; 201 183 while (imaplen > (addrsize + intsize + 1) && !match) { 202 184 /* Compare specifiers */ 203 185 match = 1; 204 - for (i = 0; i < addrsize && match; ++i) { 205 - __be32 mask = imask ? imask[i] 206 - : cpu_to_be32(0xffffffffu); 207 - match = ((addr[i] ^ imap[i]) & mask) == 0; 208 - } 209 - for (; i < (addrsize + intsize) && match; ++i) { 210 - __be32 mask = imask ? imask[i] 211 - : cpu_to_be32(0xffffffffu); 212 - match = 213 - ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; 214 - } 215 - imap += addrsize + intsize; 216 - imaplen -= addrsize + intsize; 186 + for (i = 0; i < (addrsize + intsize); i++, imaplen--) 187 + match = !((match_array[i] ^ *imap++) & imask[i]); 217 188 218 189 pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); 219 190 ··· 240 247 if (!match) 241 248 goto fail; 242 249 243 - of_node_put(old); 244 - old = of_node_get(newpar); 250 + /* 251 + * Successfully parsed an interrrupt-map translation; copy new 252 + * interrupt specifier into the out_irq structure 253 + */ 254 + of_node_put(out_irq->np); 255 + out_irq->np = of_node_get(newpar); 256 + 257 + match_array = imap - newaddrsize - newintsize; 258 + for (i = 0; i < newintsize; i++) 259 + out_irq->args[i] = be32_to_cpup(imap - newintsize + i); 260 + out_irq->args_count = intsize = newintsize; 245 261 addrsize = newaddrsize; 246 - intsize = newintsize; 247 - intspec = imap - intsize; 248 - addr = intspec - addrsize; 249 262 250 263 skiplevel: 251 264 /* Iterate again with new parent */ ··· 262 263 } 263 264 fail: 264 265 of_node_put(ipar); 265 - of_node_put(old); 266 + of_node_put(out_irq->np); 266 267 of_node_put(newpar); 267 268 268 269 return -EINVAL; ··· 275 276 * @index: index of the interrupt to resolve 276 277 * @out_irq: structure of_irq filled by this function 277 278 * 278 - * This function resolves an interrupt, walking the tree, for a given 279 - * device-tree node. It's the high level pendant to of_irq_parse_raw(). 279 + * This function resolves an interrupt for a node by walking the interrupt tree, 280 + * finding which interrupt controller node it is attached to, and returning the 281 + * interrupt specifier that can be used to retrieve a Linux IRQ number. 280 282 */ 281 283 int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) 282 284 { 283 285 struct device_node *p; 284 286 const __be32 *intspec, *tmp, *addr; 285 287 u32 intsize, intlen; 286 - int res = -EINVAL; 288 + int i, res = -EINVAL; 287 289 288 290 pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index); 289 291 ··· 320 320 if ((index + 1) * intsize > intlen) 321 321 goto out; 322 322 323 - /* Get new specifier and map it */ 324 - res = of_irq_parse_raw(p, intspec + index * intsize, intsize, 325 - addr, out_irq); 323 + /* Copy intspec into irq structure */ 324 + intspec += index * intsize; 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 332 out: 327 333 of_node_put(p); 328 334 return res;
+5 -2
drivers/of/of_pci_irq.c
··· 85 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 91 lspec_be = cpu_to_be32(lspec); 89 92 laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8)); 90 - laddr[1] = laddr[2] = cpu_to_be32(0); 91 - return of_irq_parse_raw(ppnode, &lspec_be, 1, laddr, out_irq); 93 + laddr[1] = laddr[2] = cpu_to_be32(0); 94 + return of_irq_parse_raw(laddr, out_irq); 92 95 } 93 96 EXPORT_SYMBOL_GPL(of_irq_parse_pci);
+1 -4
include/linux/of_irq.h
··· 31 31 } 32 32 #endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */ 33 33 34 - 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); 34 + extern int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq); 38 35 extern int of_irq_parse_one(struct device_node *device, int index, 39 36 struct of_phandle_args *out_irq); 40 37 extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data);