Skip to content

Commit 2361613

Browse files
committed
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 <[email protected]> Acked-by: Tony Lindgren <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]>
1 parent e6d30ab commit 2361613

File tree

4 files changed

+67
-59
lines changed

4 files changed

+67
-59
lines changed

arch/powerpc/platforms/fsl_uli1575.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@ static void hpcd_final_uli5288(struct pci_dev *dev)
322322
struct pci_controller *hose = pci_bus_to_host(dev->bus);
323323
struct device_node *hosenode = hose ? hose->dn : NULL;
324324
struct of_phandle_args oirq;
325-
int pin = 2;
326325
u32 laddr[3];
327326

328327
if (!machine_is(mpc86xx_hpcd))
@@ -331,9 +330,12 @@ static void hpcd_final_uli5288(struct pci_dev *dev)
331330
if (!hosenode)
332331
return;
333332

333+
oirq.np = hosenode;
334+
oirq.args[0] = 2;
335+
oirq.args_count = 1;
334336
laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8);
335337
laddr[1] = laddr[2] = 0;
336-
of_irq_parse_raw(hosenode, &pin, 1, laddr, &oirq);
338+
of_irq_parse_raw(laddr, &oirq);
337339
dev->irq = irq_create_of_mapping(&oirq);
338340
}
339341

drivers/of/irq.c

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -80,31 +80,32 @@ struct device_node *of_irq_find_parent(struct device_node *child)
8080
/**
8181
* of_irq_parse_raw - Low level interrupt tree parsing
8282
* @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
8785
*
8886
* Returns 0 on success and a negative number on error
8987
*
9088
* This function is a low-level interrupt tree walking function. It
9189
* can be used to do a partial walk with synthetized reg and interrupts
9290
* 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.
9494
*/
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)
9796
{
9897
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 };
100101
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
101102
int imaplen, match, i;
102103

103104
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);
106107

107-
ipar = of_node_get(parent);
108+
ipar = of_node_get(out_irq->np);
108109

109110
/* First get the #interrupt-cells property of the current cursor
110111
* 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,
127128

128129
pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
129130

130-
if (ointsize != intsize)
131+
if (out_irq->args_count != intsize)
131132
return -EINVAL;
132133

133134
/* 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,
146147

147148
pr_debug(" -> addrsize=%d\n", addrsize);
148149

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+
149165
/* Now start the actual "proper" walk of the interrupt tree */
150166
while (ipar != NULL) {
151167
/* 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,
154170
if (of_get_property(ipar, "interrupt-controller", NULL) !=
155171
NULL) {
156172
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;
162173
of_node_put(old);
163174
return 0;
164175
}
@@ -175,34 +186,16 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
175186

176187
/* Look for a mask */
177188
imask = of_get_property(ipar, "interrupt-map-mask", NULL);
178-
179-
/* If we were passed no "reg" property and we attempt to parse
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-
}
189+
if (!imask)
190+
imask = dummy_imask;
187191

188192
/* Parse interrupt-map */
189193
match = 0;
190194
while (imaplen > (addrsize + intsize + 1) && !match) {
191195
/* Compare specifiers */
192196
match = 1;
193-
for (i = 0; i < addrsize && match; ++i) {
194-
__be32 mask = imask ? 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;
197+
for (i = 0; i < (addrsize + intsize); i++, imaplen--)
198+
match = !((match_array[i] ^ *imap++) & imask[i]);
206199

207200
pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
208201

@@ -247,12 +240,18 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
247240
if (!match)
248241
goto fail;
249242

250-
of_node_put(old);
251-
old = of_node_get(newpar);
243+
/*
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;
252254
addrsize = newaddrsize;
253-
intsize = newintsize;
254-
intspec = imap - intsize;
255-
addr = intspec - addrsize;
256255

257256
skiplevel:
258257
/* Iterate again with new parent */
@@ -263,7 +262,7 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
263262
}
264263
fail:
265264
of_node_put(ipar);
266-
of_node_put(old);
265+
of_node_put(out_irq->np);
267266
of_node_put(newpar);
268267

269268
return -EINVAL;
@@ -276,15 +275,16 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw);
276275
* @index: index of the interrupt to resolve
277276
* @out_irq: structure of_irq filled by this function
278277
*
279-
* This function resolves an interrupt, walking the tree, for a given
280-
* device-tree node. It's the high level pendant to of_irq_parse_raw().
278+
* This function resolves an interrupt for a node by walking the interrupt tree,
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.
281281
*/
282282
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
283283
{
284284
struct device_node *p;
285285
const __be32 *intspec, *tmp, *addr;
286286
u32 intsize, intlen;
287-
int res = -EINVAL;
287+
int i, res = -EINVAL;
288288

289289
pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
290290

@@ -320,9 +320,15 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
320320
if ((index + 1) * intsize > intlen)
321321
goto out;
322322

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);
326332
out:
327333
of_node_put(p);
328334
return res;

drivers/of/of_pci_irq.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,12 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
8585
pdev = ppdev;
8686
}
8787

88+
out_irq->np = ppnode;
89+
out_irq->args_count = 1;
90+
out_irq->args[0] = lspec;
8891
lspec_be = cpu_to_be32(lspec);
8992
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);
9295
}
9396
EXPORT_SYMBOL_GPL(of_irq_parse_pci);

include/linux/of_irq.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ static inline int of_irq_parse_oldworld(struct device_node *device, int index,
3131
}
3232
#endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */
3333

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);
3835
extern int of_irq_parse_one(struct device_node *device, int index,
3936
struct of_phandle_args *out_irq);
4037
extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data);

0 commit comments

Comments
 (0)