162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Derived from arch/i386/kernel/irq.c
462306a36Sopenharmony_ci *    Copyright (C) 1992 Linus Torvalds
562306a36Sopenharmony_ci *  Adapted from arch/i386 by Gary Thomas
662306a36Sopenharmony_ci *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
762306a36Sopenharmony_ci *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
862306a36Sopenharmony_ci *    Copyright (C) 1996-2001 Cort Dougan
962306a36Sopenharmony_ci *  Adapted for Power Macintosh by Paul Mackerras
1062306a36Sopenharmony_ci *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * This file contains the code used to make IRQ descriptions in the
1362306a36Sopenharmony_ci * device tree to actual irq numbers on an interrupt controller
1462306a36Sopenharmony_ci * driver.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define pr_fmt(fmt)	"OF: " fmt
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/device.h>
2062306a36Sopenharmony_ci#include <linux/errno.h>
2162306a36Sopenharmony_ci#include <linux/list.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/of_irq.h>
2562306a36Sopenharmony_ci#include <linux/string.h>
2662306a36Sopenharmony_ci#include <linux/slab.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/**
2962306a36Sopenharmony_ci * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
3062306a36Sopenharmony_ci * @dev: Device node of the device whose interrupt is to be mapped
3162306a36Sopenharmony_ci * @index: Index of the interrupt to map
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * This function is a wrapper that chains of_irq_parse_one() and
3462306a36Sopenharmony_ci * irq_create_of_mapping() to make things easier to callers
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_ciunsigned int irq_of_parse_and_map(struct device_node *dev, int index)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct of_phandle_args oirq;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (of_irq_parse_one(dev, index, &oirq))
4162306a36Sopenharmony_ci		return 0;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return irq_create_of_mapping(&oirq);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(irq_of_parse_and_map);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci * of_irq_find_parent - Given a device node, find its interrupt parent node
4962306a36Sopenharmony_ci * @child: pointer to device node
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Return: A pointer to the interrupt parent node, or NULL if the interrupt
5262306a36Sopenharmony_ci * parent could not be determined.
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistruct device_node *of_irq_find_parent(struct device_node *child)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct device_node *p;
5762306a36Sopenharmony_ci	phandle parent;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (!of_node_get(child))
6062306a36Sopenharmony_ci		return NULL;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	do {
6362306a36Sopenharmony_ci		if (of_property_read_u32(child, "interrupt-parent", &parent)) {
6462306a36Sopenharmony_ci			p = of_get_parent(child);
6562306a36Sopenharmony_ci		} else	{
6662306a36Sopenharmony_ci			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
6762306a36Sopenharmony_ci				p = of_node_get(of_irq_dflt_pic);
6862306a36Sopenharmony_ci			else
6962306a36Sopenharmony_ci				p = of_find_node_by_phandle(parent);
7062306a36Sopenharmony_ci		}
7162306a36Sopenharmony_ci		of_node_put(child);
7262306a36Sopenharmony_ci		child = p;
7362306a36Sopenharmony_ci	} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return p;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_find_parent);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * These interrupt controllers abuse interrupt-map for unspeakable
8162306a36Sopenharmony_ci * reasons and rely on the core code to *ignore* it (the drivers do
8262306a36Sopenharmony_ci * their own parsing of the property).
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * If you think of adding to the list for something *new*, think
8562306a36Sopenharmony_ci * again. There is a high chance that you will be sent back to the
8662306a36Sopenharmony_ci * drawing board.
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistatic const char * const of_irq_imap_abusers[] = {
8962306a36Sopenharmony_ci	"CBEA,platform-spider-pic",
9062306a36Sopenharmony_ci	"sti,platform-spider-pic",
9162306a36Sopenharmony_ci	"realtek,rtl-intc",
9262306a36Sopenharmony_ci	"fsl,ls1021a-extirq",
9362306a36Sopenharmony_ci	"fsl,ls1043a-extirq",
9462306a36Sopenharmony_ci	"fsl,ls1088a-extirq",
9562306a36Sopenharmony_ci	"renesas,rza1-irqc",
9662306a36Sopenharmony_ci	NULL,
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/**
10062306a36Sopenharmony_ci * of_irq_parse_raw - Low level interrupt tree parsing
10162306a36Sopenharmony_ci * @addr:	address specifier (start of "reg" property of the device) in be32 format
10262306a36Sopenharmony_ci * @out_irq:	structure of_phandle_args updated by this function
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * This function is a low-level interrupt tree walking function. It
10562306a36Sopenharmony_ci * can be used to do a partial walk with synthetized reg and interrupts
10662306a36Sopenharmony_ci * properties, for example when resolving PCI interrupts when no device
10762306a36Sopenharmony_ci * node exist for the parent. It takes an interrupt specifier structure as
10862306a36Sopenharmony_ci * input, walks the tree looking for any interrupt-map properties, translates
10962306a36Sopenharmony_ci * the specifier for each map, and then returns the translated map.
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * Return: 0 on success and a negative number on error
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_ciint of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
11662306a36Sopenharmony_ci	__be32 initial_match_array[MAX_PHANDLE_ARGS];
11762306a36Sopenharmony_ci	const __be32 *match_array = initial_match_array;
11862306a36Sopenharmony_ci	const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
11962306a36Sopenharmony_ci	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
12062306a36Sopenharmony_ci	int imaplen, match, i, rc = -EINVAL;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#ifdef DEBUG
12362306a36Sopenharmony_ci	of_print_phandle_args("of_irq_parse_raw: ", out_irq);
12462306a36Sopenharmony_ci#endif
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	ipar = of_node_get(out_irq->np);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* First get the #interrupt-cells property of the current cursor
12962306a36Sopenharmony_ci	 * that tells us how to interpret the passed-in intspec. If there
13062306a36Sopenharmony_ci	 * is none, we are nice and just walk up the tree
13162306a36Sopenharmony_ci	 */
13262306a36Sopenharmony_ci	do {
13362306a36Sopenharmony_ci		if (!of_property_read_u32(ipar, "#interrupt-cells", &intsize))
13462306a36Sopenharmony_ci			break;
13562306a36Sopenharmony_ci		tnode = ipar;
13662306a36Sopenharmony_ci		ipar = of_irq_find_parent(ipar);
13762306a36Sopenharmony_ci		of_node_put(tnode);
13862306a36Sopenharmony_ci	} while (ipar);
13962306a36Sopenharmony_ci	if (ipar == NULL) {
14062306a36Sopenharmony_ci		pr_debug(" -> no parent found !\n");
14162306a36Sopenharmony_ci		goto fail;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	pr_debug("of_irq_parse_raw: ipar=%pOF, size=%d\n", ipar, intsize);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (out_irq->args_count != intsize)
14762306a36Sopenharmony_ci		goto fail;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Look for this #address-cells. We have to implement the old linux
15062306a36Sopenharmony_ci	 * trick of looking for the parent here as some device-trees rely on it
15162306a36Sopenharmony_ci	 */
15262306a36Sopenharmony_ci	old = of_node_get(ipar);
15362306a36Sopenharmony_ci	do {
15462306a36Sopenharmony_ci		tmp = of_get_property(old, "#address-cells", NULL);
15562306a36Sopenharmony_ci		tnode = of_get_parent(old);
15662306a36Sopenharmony_ci		of_node_put(old);
15762306a36Sopenharmony_ci		old = tnode;
15862306a36Sopenharmony_ci	} while (old && tmp == NULL);
15962306a36Sopenharmony_ci	of_node_put(old);
16062306a36Sopenharmony_ci	old = NULL;
16162306a36Sopenharmony_ci	addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	pr_debug(" -> addrsize=%d\n", addrsize);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Range check so that the temporary buffer doesn't overflow */
16662306a36Sopenharmony_ci	if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) {
16762306a36Sopenharmony_ci		rc = -EFAULT;
16862306a36Sopenharmony_ci		goto fail;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Precalculate the match array - this simplifies match loop */
17262306a36Sopenharmony_ci	for (i = 0; i < addrsize; i++)
17362306a36Sopenharmony_ci		initial_match_array[i] = addr ? addr[i] : 0;
17462306a36Sopenharmony_ci	for (i = 0; i < intsize; i++)
17562306a36Sopenharmony_ci		initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* Now start the actual "proper" walk of the interrupt tree */
17862306a36Sopenharmony_ci	while (ipar != NULL) {
17962306a36Sopenharmony_ci		/*
18062306a36Sopenharmony_ci		 * Now check if cursor is an interrupt-controller and
18162306a36Sopenharmony_ci		 * if it is then we are done, unless there is an
18262306a36Sopenharmony_ci		 * interrupt-map which takes precedence except on one
18362306a36Sopenharmony_ci		 * of these broken platforms that want to parse
18462306a36Sopenharmony_ci		 * interrupt-map themselves for $reason.
18562306a36Sopenharmony_ci		 */
18662306a36Sopenharmony_ci		bool intc = of_property_read_bool(ipar, "interrupt-controller");
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		imap = of_get_property(ipar, "interrupt-map", &imaplen);
18962306a36Sopenharmony_ci		if (intc &&
19062306a36Sopenharmony_ci		    (!imap || of_device_compatible_match(ipar, of_irq_imap_abusers))) {
19162306a36Sopenharmony_ci			pr_debug(" -> got it !\n");
19262306a36Sopenharmony_ci			return 0;
19362306a36Sopenharmony_ci		}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		/*
19662306a36Sopenharmony_ci		 * interrupt-map parsing does not work without a reg
19762306a36Sopenharmony_ci		 * property when #address-cells != 0
19862306a36Sopenharmony_ci		 */
19962306a36Sopenharmony_ci		if (addrsize && !addr) {
20062306a36Sopenharmony_ci			pr_debug(" -> no reg passed in when needed !\n");
20162306a36Sopenharmony_ci			goto fail;
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		/* No interrupt map, check for an interrupt parent */
20562306a36Sopenharmony_ci		if (imap == NULL) {
20662306a36Sopenharmony_ci			pr_debug(" -> no map, getting parent\n");
20762306a36Sopenharmony_ci			newpar = of_irq_find_parent(ipar);
20862306a36Sopenharmony_ci			goto skiplevel;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci		imaplen /= sizeof(u32);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		/* Look for a mask */
21362306a36Sopenharmony_ci		imask = of_get_property(ipar, "interrupt-map-mask", NULL);
21462306a36Sopenharmony_ci		if (!imask)
21562306a36Sopenharmony_ci			imask = dummy_imask;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		/* Parse interrupt-map */
21862306a36Sopenharmony_ci		match = 0;
21962306a36Sopenharmony_ci		while (imaplen > (addrsize + intsize + 1) && !match) {
22062306a36Sopenharmony_ci			/* Compare specifiers */
22162306a36Sopenharmony_ci			match = 1;
22262306a36Sopenharmony_ci			for (i = 0; i < (addrsize + intsize); i++, imaplen--)
22362306a36Sopenharmony_ci				match &= !((match_array[i] ^ *imap++) & imask[i]);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci			/* Get the interrupt parent */
22862306a36Sopenharmony_ci			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
22962306a36Sopenharmony_ci				newpar = of_node_get(of_irq_dflt_pic);
23062306a36Sopenharmony_ci			else
23162306a36Sopenharmony_ci				newpar = of_find_node_by_phandle(be32_to_cpup(imap));
23262306a36Sopenharmony_ci			imap++;
23362306a36Sopenharmony_ci			--imaplen;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci			/* Check if not found */
23662306a36Sopenharmony_ci			if (newpar == NULL) {
23762306a36Sopenharmony_ci				pr_debug(" -> imap parent not found !\n");
23862306a36Sopenharmony_ci				goto fail;
23962306a36Sopenharmony_ci			}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci			if (!of_device_is_available(newpar))
24262306a36Sopenharmony_ci				match = 0;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci			/* Get #interrupt-cells and #address-cells of new
24562306a36Sopenharmony_ci			 * parent
24662306a36Sopenharmony_ci			 */
24762306a36Sopenharmony_ci			if (of_property_read_u32(newpar, "#interrupt-cells",
24862306a36Sopenharmony_ci						 &newintsize)) {
24962306a36Sopenharmony_ci				pr_debug(" -> parent lacks #interrupt-cells!\n");
25062306a36Sopenharmony_ci				goto fail;
25162306a36Sopenharmony_ci			}
25262306a36Sopenharmony_ci			if (of_property_read_u32(newpar, "#address-cells",
25362306a36Sopenharmony_ci						 &newaddrsize))
25462306a36Sopenharmony_ci				newaddrsize = 0;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci			pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
25762306a36Sopenharmony_ci			    newintsize, newaddrsize);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci			/* Check for malformed properties */
26062306a36Sopenharmony_ci			if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
26162306a36Sopenharmony_ci			    || (imaplen < (newaddrsize + newintsize))) {
26262306a36Sopenharmony_ci				rc = -EFAULT;
26362306a36Sopenharmony_ci				goto fail;
26462306a36Sopenharmony_ci			}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci			imap += newaddrsize + newintsize;
26762306a36Sopenharmony_ci			imaplen -= newaddrsize + newintsize;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci			pr_debug(" -> imaplen=%d\n", imaplen);
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci		if (!match) {
27262306a36Sopenharmony_ci			if (intc) {
27362306a36Sopenharmony_ci				/*
27462306a36Sopenharmony_ci				 * The PASEMI Nemo is a known offender, so
27562306a36Sopenharmony_ci				 * let's only warn for anyone else.
27662306a36Sopenharmony_ci				 */
27762306a36Sopenharmony_ci				WARN(!IS_ENABLED(CONFIG_PPC_PASEMI),
27862306a36Sopenharmony_ci				     "%pOF interrupt-map failed, using interrupt-controller\n",
27962306a36Sopenharmony_ci				     ipar);
28062306a36Sopenharmony_ci				return 0;
28162306a36Sopenharmony_ci			}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci			goto fail;
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		/*
28762306a36Sopenharmony_ci		 * Successfully parsed an interrupt-map translation; copy new
28862306a36Sopenharmony_ci		 * interrupt specifier into the out_irq structure
28962306a36Sopenharmony_ci		 */
29062306a36Sopenharmony_ci		match_array = imap - newaddrsize - newintsize;
29162306a36Sopenharmony_ci		for (i = 0; i < newintsize; i++)
29262306a36Sopenharmony_ci			out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
29362306a36Sopenharmony_ci		out_irq->args_count = intsize = newintsize;
29462306a36Sopenharmony_ci		addrsize = newaddrsize;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		if (ipar == newpar) {
29762306a36Sopenharmony_ci			pr_debug("%pOF interrupt-map entry to self\n", ipar);
29862306a36Sopenharmony_ci			return 0;
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	skiplevel:
30262306a36Sopenharmony_ci		/* Iterate again with new parent */
30362306a36Sopenharmony_ci		out_irq->np = newpar;
30462306a36Sopenharmony_ci		pr_debug(" -> new parent: %pOF\n", newpar);
30562306a36Sopenharmony_ci		of_node_put(ipar);
30662306a36Sopenharmony_ci		ipar = newpar;
30762306a36Sopenharmony_ci		newpar = NULL;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci	rc = -ENOENT; /* No interrupt-map found */
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci fail:
31262306a36Sopenharmony_ci	of_node_put(ipar);
31362306a36Sopenharmony_ci	of_node_put(newpar);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return rc;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_parse_raw);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/**
32062306a36Sopenharmony_ci * of_irq_parse_one - Resolve an interrupt for a device
32162306a36Sopenharmony_ci * @device: the device whose interrupt is to be resolved
32262306a36Sopenharmony_ci * @index: index of the interrupt to resolve
32362306a36Sopenharmony_ci * @out_irq: structure of_phandle_args filled by this function
32462306a36Sopenharmony_ci *
32562306a36Sopenharmony_ci * This function resolves an interrupt for a node by walking the interrupt tree,
32662306a36Sopenharmony_ci * finding which interrupt controller node it is attached to, and returning the
32762306a36Sopenharmony_ci * interrupt specifier that can be used to retrieve a Linux IRQ number.
32862306a36Sopenharmony_ci */
32962306a36Sopenharmony_ciint of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct device_node *p;
33262306a36Sopenharmony_ci	const __be32 *addr;
33362306a36Sopenharmony_ci	u32 intsize;
33462306a36Sopenharmony_ci	int i, res;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* OldWorld mac stuff is "special", handle out of line */
33962306a36Sopenharmony_ci	if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
34062306a36Sopenharmony_ci		return of_irq_parse_oldworld(device, index, out_irq);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Get the reg property (if any) */
34362306a36Sopenharmony_ci	addr = of_get_property(device, "reg", NULL);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Try the new-style interrupts-extended first */
34662306a36Sopenharmony_ci	res = of_parse_phandle_with_args(device, "interrupts-extended",
34762306a36Sopenharmony_ci					"#interrupt-cells", index, out_irq);
34862306a36Sopenharmony_ci	if (!res)
34962306a36Sopenharmony_ci		return of_irq_parse_raw(addr, out_irq);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Look for the interrupt parent. */
35262306a36Sopenharmony_ci	p = of_irq_find_parent(device);
35362306a36Sopenharmony_ci	if (p == NULL)
35462306a36Sopenharmony_ci		return -EINVAL;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Get size of interrupt specifier */
35762306a36Sopenharmony_ci	if (of_property_read_u32(p, "#interrupt-cells", &intsize)) {
35862306a36Sopenharmony_ci		res = -EINVAL;
35962306a36Sopenharmony_ci		goto out;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* Copy intspec into irq structure */
36562306a36Sopenharmony_ci	out_irq->np = p;
36662306a36Sopenharmony_ci	out_irq->args_count = intsize;
36762306a36Sopenharmony_ci	for (i = 0; i < intsize; i++) {
36862306a36Sopenharmony_ci		res = of_property_read_u32_index(device, "interrupts",
36962306a36Sopenharmony_ci						 (index * intsize) + i,
37062306a36Sopenharmony_ci						 out_irq->args + i);
37162306a36Sopenharmony_ci		if (res)
37262306a36Sopenharmony_ci			goto out;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	pr_debug(" intspec=%d\n", *out_irq->args);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Check if there are any interrupt-map translations to process */
37962306a36Sopenharmony_ci	res = of_irq_parse_raw(addr, out_irq);
38062306a36Sopenharmony_ci out:
38162306a36Sopenharmony_ci	of_node_put(p);
38262306a36Sopenharmony_ci	return res;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_parse_one);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * of_irq_to_resource - Decode a node's IRQ and return it as a resource
38862306a36Sopenharmony_ci * @dev: pointer to device tree node
38962306a36Sopenharmony_ci * @index: zero-based index of the irq
39062306a36Sopenharmony_ci * @r: pointer to resource structure to return result into.
39162306a36Sopenharmony_ci */
39262306a36Sopenharmony_ciint of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	int irq = of_irq_get(dev, index);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (irq < 0)
39762306a36Sopenharmony_ci		return irq;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Only dereference the resource if both the
40062306a36Sopenharmony_ci	 * resource and the irq are valid. */
40162306a36Sopenharmony_ci	if (r && irq) {
40262306a36Sopenharmony_ci		const char *name = NULL;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		memset(r, 0, sizeof(*r));
40562306a36Sopenharmony_ci		/*
40662306a36Sopenharmony_ci		 * Get optional "interrupt-names" property to add a name
40762306a36Sopenharmony_ci		 * to the resource.
40862306a36Sopenharmony_ci		 */
40962306a36Sopenharmony_ci		of_property_read_string_index(dev, "interrupt-names", index,
41062306a36Sopenharmony_ci					      &name);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		r->start = r->end = irq;
41362306a36Sopenharmony_ci		r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq));
41462306a36Sopenharmony_ci		r->name = name ? name : of_node_full_name(dev);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return irq;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_to_resource);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/**
42262306a36Sopenharmony_ci * of_irq_get - Decode a node's IRQ and return it as a Linux IRQ number
42362306a36Sopenharmony_ci * @dev: pointer to device tree node
42462306a36Sopenharmony_ci * @index: zero-based index of the IRQ
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * Return: Linux IRQ number on success, or 0 on the IRQ mapping failure, or
42762306a36Sopenharmony_ci * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
42862306a36Sopenharmony_ci * of any other failure.
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_ciint of_irq_get(struct device_node *dev, int index)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	int rc;
43362306a36Sopenharmony_ci	struct of_phandle_args oirq;
43462306a36Sopenharmony_ci	struct irq_domain *domain;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	rc = of_irq_parse_one(dev, index, &oirq);
43762306a36Sopenharmony_ci	if (rc)
43862306a36Sopenharmony_ci		return rc;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	domain = irq_find_host(oirq.np);
44162306a36Sopenharmony_ci	if (!domain) {
44262306a36Sopenharmony_ci		rc = -EPROBE_DEFER;
44362306a36Sopenharmony_ci		goto out;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	rc = irq_create_of_mapping(&oirq);
44762306a36Sopenharmony_ciout:
44862306a36Sopenharmony_ci	of_node_put(oirq.np);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return rc;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_get);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/**
45562306a36Sopenharmony_ci * of_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
45662306a36Sopenharmony_ci * @dev: pointer to device tree node
45762306a36Sopenharmony_ci * @name: IRQ name
45862306a36Sopenharmony_ci *
45962306a36Sopenharmony_ci * Return: Linux IRQ number on success, or 0 on the IRQ mapping failure, or
46062306a36Sopenharmony_ci * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
46162306a36Sopenharmony_ci * of any other failure.
46262306a36Sopenharmony_ci */
46362306a36Sopenharmony_ciint of_irq_get_byname(struct device_node *dev, const char *name)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	int index;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (unlikely(!name))
46862306a36Sopenharmony_ci		return -EINVAL;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	index = of_property_match_string(dev, "interrupt-names", name);
47162306a36Sopenharmony_ci	if (index < 0)
47262306a36Sopenharmony_ci		return index;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	return of_irq_get(dev, index);
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_get_byname);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * of_irq_count - Count the number of IRQs a node uses
48062306a36Sopenharmony_ci * @dev: pointer to device tree node
48162306a36Sopenharmony_ci */
48262306a36Sopenharmony_ciint of_irq_count(struct device_node *dev)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct of_phandle_args irq;
48562306a36Sopenharmony_ci	int nr = 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	while (of_irq_parse_one(dev, nr, &irq) == 0)
48862306a36Sopenharmony_ci		nr++;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	return nr;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/**
49462306a36Sopenharmony_ci * of_irq_to_resource_table - Fill in resource table with node's IRQ info
49562306a36Sopenharmony_ci * @dev: pointer to device tree node
49662306a36Sopenharmony_ci * @res: array of resources to fill in
49762306a36Sopenharmony_ci * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
49862306a36Sopenharmony_ci *
49962306a36Sopenharmony_ci * Return: The size of the filled in table (up to @nr_irqs).
50062306a36Sopenharmony_ci */
50162306a36Sopenharmony_ciint of_irq_to_resource_table(struct device_node *dev, struct resource *res,
50262306a36Sopenharmony_ci		int nr_irqs)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	int i;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	for (i = 0; i < nr_irqs; i++, res++)
50762306a36Sopenharmony_ci		if (of_irq_to_resource(dev, i, res) <= 0)
50862306a36Sopenharmony_ci			break;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	return i;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_to_resource_table);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistruct of_intc_desc {
51562306a36Sopenharmony_ci	struct list_head	list;
51662306a36Sopenharmony_ci	of_irq_init_cb_t	irq_init_cb;
51762306a36Sopenharmony_ci	struct device_node	*dev;
51862306a36Sopenharmony_ci	struct device_node	*interrupt_parent;
51962306a36Sopenharmony_ci};
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci/**
52262306a36Sopenharmony_ci * of_irq_init - Scan and init matching interrupt controllers in DT
52362306a36Sopenharmony_ci * @matches: 0 terminated array of nodes to match and init function to call
52462306a36Sopenharmony_ci *
52562306a36Sopenharmony_ci * This function scans the device tree for matching interrupt controller nodes,
52662306a36Sopenharmony_ci * and calls their initialization functions in order with parents first.
52762306a36Sopenharmony_ci */
52862306a36Sopenharmony_civoid __init of_irq_init(const struct of_device_id *matches)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	const struct of_device_id *match;
53162306a36Sopenharmony_ci	struct device_node *np, *parent = NULL;
53262306a36Sopenharmony_ci	struct of_intc_desc *desc, *temp_desc;
53362306a36Sopenharmony_ci	struct list_head intc_desc_list, intc_parent_list;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	INIT_LIST_HEAD(&intc_desc_list);
53662306a36Sopenharmony_ci	INIT_LIST_HEAD(&intc_parent_list);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	for_each_matching_node_and_match(np, matches, &match) {
53962306a36Sopenharmony_ci		if (!of_property_read_bool(np, "interrupt-controller") ||
54062306a36Sopenharmony_ci				!of_device_is_available(np))
54162306a36Sopenharmony_ci			continue;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		if (WARN(!match->data, "of_irq_init: no init function for %s\n",
54462306a36Sopenharmony_ci			 match->compatible))
54562306a36Sopenharmony_ci			continue;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/*
54862306a36Sopenharmony_ci		 * Here, we allocate and populate an of_intc_desc with the node
54962306a36Sopenharmony_ci		 * pointer, interrupt-parent device_node etc.
55062306a36Sopenharmony_ci		 */
55162306a36Sopenharmony_ci		desc = kzalloc(sizeof(*desc), GFP_KERNEL);
55262306a36Sopenharmony_ci		if (!desc) {
55362306a36Sopenharmony_ci			of_node_put(np);
55462306a36Sopenharmony_ci			goto err;
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		desc->irq_init_cb = match->data;
55862306a36Sopenharmony_ci		desc->dev = of_node_get(np);
55962306a36Sopenharmony_ci		/*
56062306a36Sopenharmony_ci		 * interrupts-extended can reference multiple parent domains.
56162306a36Sopenharmony_ci		 * Arbitrarily pick the first one; assume any other parents
56262306a36Sopenharmony_ci		 * are the same distance away from the root irq controller.
56362306a36Sopenharmony_ci		 */
56462306a36Sopenharmony_ci		desc->interrupt_parent = of_parse_phandle(np, "interrupts-extended", 0);
56562306a36Sopenharmony_ci		if (!desc->interrupt_parent)
56662306a36Sopenharmony_ci			desc->interrupt_parent = of_irq_find_parent(np);
56762306a36Sopenharmony_ci		if (desc->interrupt_parent == np) {
56862306a36Sopenharmony_ci			of_node_put(desc->interrupt_parent);
56962306a36Sopenharmony_ci			desc->interrupt_parent = NULL;
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci		list_add_tail(&desc->list, &intc_desc_list);
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/*
57562306a36Sopenharmony_ci	 * The root irq controller is the one without an interrupt-parent.
57662306a36Sopenharmony_ci	 * That one goes first, followed by the controllers that reference it,
57762306a36Sopenharmony_ci	 * followed by the ones that reference the 2nd level controllers, etc.
57862306a36Sopenharmony_ci	 */
57962306a36Sopenharmony_ci	while (!list_empty(&intc_desc_list)) {
58062306a36Sopenharmony_ci		/*
58162306a36Sopenharmony_ci		 * Process all controllers with the current 'parent'.
58262306a36Sopenharmony_ci		 * First pass will be looking for NULL as the parent.
58362306a36Sopenharmony_ci		 * The assumption is that NULL parent means a root controller.
58462306a36Sopenharmony_ci		 */
58562306a36Sopenharmony_ci		list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
58662306a36Sopenharmony_ci			int ret;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci			if (desc->interrupt_parent != parent)
58962306a36Sopenharmony_ci				continue;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci			list_del(&desc->list);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci			of_node_set_flag(desc->dev, OF_POPULATED);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci			pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
59662306a36Sopenharmony_ci				 desc->dev,
59762306a36Sopenharmony_ci				 desc->dev, desc->interrupt_parent);
59862306a36Sopenharmony_ci			ret = desc->irq_init_cb(desc->dev,
59962306a36Sopenharmony_ci						desc->interrupt_parent);
60062306a36Sopenharmony_ci			if (ret) {
60162306a36Sopenharmony_ci				pr_err("%s: Failed to init %pOF (%p), parent %p\n",
60262306a36Sopenharmony_ci				       __func__, desc->dev, desc->dev,
60362306a36Sopenharmony_ci				       desc->interrupt_parent);
60462306a36Sopenharmony_ci				of_node_clear_flag(desc->dev, OF_POPULATED);
60562306a36Sopenharmony_ci				kfree(desc);
60662306a36Sopenharmony_ci				continue;
60762306a36Sopenharmony_ci			}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci			/*
61062306a36Sopenharmony_ci			 * This one is now set up; add it to the parent list so
61162306a36Sopenharmony_ci			 * its children can get processed in a subsequent pass.
61262306a36Sopenharmony_ci			 */
61362306a36Sopenharmony_ci			list_add_tail(&desc->list, &intc_parent_list);
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		/* Get the next pending parent that might have children */
61762306a36Sopenharmony_ci		desc = list_first_entry_or_null(&intc_parent_list,
61862306a36Sopenharmony_ci						typeof(*desc), list);
61962306a36Sopenharmony_ci		if (!desc) {
62062306a36Sopenharmony_ci			pr_err("of_irq_init: children remain, but no parents\n");
62162306a36Sopenharmony_ci			break;
62262306a36Sopenharmony_ci		}
62362306a36Sopenharmony_ci		list_del(&desc->list);
62462306a36Sopenharmony_ci		parent = desc->dev;
62562306a36Sopenharmony_ci		kfree(desc);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
62962306a36Sopenharmony_ci		list_del(&desc->list);
63062306a36Sopenharmony_ci		kfree(desc);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_cierr:
63362306a36Sopenharmony_ci	list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
63462306a36Sopenharmony_ci		list_del(&desc->list);
63562306a36Sopenharmony_ci		of_node_put(desc->dev);
63662306a36Sopenharmony_ci		kfree(desc);
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic u32 __of_msi_map_id(struct device *dev, struct device_node **np,
64162306a36Sopenharmony_ci			    u32 id_in)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct device *parent_dev;
64462306a36Sopenharmony_ci	u32 id_out = id_in;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/*
64762306a36Sopenharmony_ci	 * Walk up the device parent links looking for one with a
64862306a36Sopenharmony_ci	 * "msi-map" property.
64962306a36Sopenharmony_ci	 */
65062306a36Sopenharmony_ci	for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent)
65162306a36Sopenharmony_ci		if (!of_map_id(parent_dev->of_node, id_in, "msi-map",
65262306a36Sopenharmony_ci				"msi-map-mask", np, &id_out))
65362306a36Sopenharmony_ci			break;
65462306a36Sopenharmony_ci	return id_out;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci/**
65862306a36Sopenharmony_ci * of_msi_map_id - Map a MSI ID for a device.
65962306a36Sopenharmony_ci * @dev: device for which the mapping is to be done.
66062306a36Sopenharmony_ci * @msi_np: device node of the expected msi controller.
66162306a36Sopenharmony_ci * @id_in: unmapped MSI ID for the device.
66262306a36Sopenharmony_ci *
66362306a36Sopenharmony_ci * Walk up the device hierarchy looking for devices with a "msi-map"
66462306a36Sopenharmony_ci * property.  If found, apply the mapping to @id_in.
66562306a36Sopenharmony_ci *
66662306a36Sopenharmony_ci * Return: The mapped MSI ID.
66762306a36Sopenharmony_ci */
66862306a36Sopenharmony_ciu32 of_msi_map_id(struct device *dev, struct device_node *msi_np, u32 id_in)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	return __of_msi_map_id(dev, &msi_np, id_in);
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci/**
67462306a36Sopenharmony_ci * of_msi_map_get_device_domain - Use msi-map to find the relevant MSI domain
67562306a36Sopenharmony_ci * @dev: device for which the mapping is to be done.
67662306a36Sopenharmony_ci * @id: Device ID.
67762306a36Sopenharmony_ci * @bus_token: Bus token
67862306a36Sopenharmony_ci *
67962306a36Sopenharmony_ci * Walk up the device hierarchy looking for devices with a "msi-map"
68062306a36Sopenharmony_ci * property.
68162306a36Sopenharmony_ci *
68262306a36Sopenharmony_ci * Returns: the MSI domain for this device (or NULL on failure)
68362306a36Sopenharmony_ci */
68462306a36Sopenharmony_cistruct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 id,
68562306a36Sopenharmony_ci						u32 bus_token)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	struct device_node *np = NULL;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	__of_msi_map_id(dev, &np, id);
69062306a36Sopenharmony_ci	return irq_find_matching_host(np, bus_token);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci/**
69462306a36Sopenharmony_ci * of_msi_get_domain - Use msi-parent to find the relevant MSI domain
69562306a36Sopenharmony_ci * @dev: device for which the domain is requested
69662306a36Sopenharmony_ci * @np: device node for @dev
69762306a36Sopenharmony_ci * @token: bus type for this domain
69862306a36Sopenharmony_ci *
69962306a36Sopenharmony_ci * Parse the msi-parent property (both the simple and the complex
70062306a36Sopenharmony_ci * versions), and returns the corresponding MSI domain.
70162306a36Sopenharmony_ci *
70262306a36Sopenharmony_ci * Returns: the MSI domain for this device (or NULL on failure).
70362306a36Sopenharmony_ci */
70462306a36Sopenharmony_cistruct irq_domain *of_msi_get_domain(struct device *dev,
70562306a36Sopenharmony_ci				     struct device_node *np,
70662306a36Sopenharmony_ci				     enum irq_domain_bus_token token)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct device_node *msi_np;
70962306a36Sopenharmony_ci	struct irq_domain *d;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/* Check for a single msi-parent property */
71262306a36Sopenharmony_ci	msi_np = of_parse_phandle(np, "msi-parent", 0);
71362306a36Sopenharmony_ci	if (msi_np && !of_property_read_bool(msi_np, "#msi-cells")) {
71462306a36Sopenharmony_ci		d = irq_find_matching_host(msi_np, token);
71562306a36Sopenharmony_ci		if (!d)
71662306a36Sopenharmony_ci			of_node_put(msi_np);
71762306a36Sopenharmony_ci		return d;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (token == DOMAIN_BUS_PLATFORM_MSI) {
72162306a36Sopenharmony_ci		/* Check for the complex msi-parent version */
72262306a36Sopenharmony_ci		struct of_phandle_args args;
72362306a36Sopenharmony_ci		int index = 0;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		while (!of_parse_phandle_with_args(np, "msi-parent",
72662306a36Sopenharmony_ci						   "#msi-cells",
72762306a36Sopenharmony_ci						   index, &args)) {
72862306a36Sopenharmony_ci			d = irq_find_matching_host(args.np, token);
72962306a36Sopenharmony_ci			if (d)
73062306a36Sopenharmony_ci				return d;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci			of_node_put(args.np);
73362306a36Sopenharmony_ci			index++;
73462306a36Sopenharmony_ci		}
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	return NULL;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_msi_get_domain);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci/**
74262306a36Sopenharmony_ci * of_msi_configure - Set the msi_domain field of a device
74362306a36Sopenharmony_ci * @dev: device structure to associate with an MSI irq domain
74462306a36Sopenharmony_ci * @np: device node for that device
74562306a36Sopenharmony_ci */
74662306a36Sopenharmony_civoid of_msi_configure(struct device *dev, struct device_node *np)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	dev_set_msi_domain(dev,
74962306a36Sopenharmony_ci			   of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI));
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_msi_configure);
752