mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
of/irq: Stop the MSI walk at the first msi-parent
of_check_msi_parent() returns -EINVAL both when the msi-parent names a controller other than the one the caller filters on and when #msi-cells isn't 0, so of_msi_xlate() can't tell the two apart and carries on up the hierarchy. An ancestor's msi-map then maps the device onto a controller its own node didn't name. Hand the parsed specifier back to of_msi_xlate(), which owns the reference as it already does on the msi-map path, and end the walk at any node that declares an msi-parent. Reported-by: Sashiko <sashiko-bot@kernel.org> Closes: https://lore.kernel.org/all/20260904074800.875391F00A3F@smtp.kernel.org/ Suggested-by: Lorenzo Pieralisi <lpieralisi@kernel.org> Link: https://lore.kernel.org/all/apqnaNmeuUjfC8Ng@red-moon/ Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev> Link: https://patch.msgid.link/20260907112944.313618-3-fuad.tabba@linux.dev Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
This commit is contained in:
parent
cbe0f79dca
commit
833aaa4790
|
|
@ -765,34 +765,27 @@ void __init of_irq_init(const struct of_device_id *matches)
|
|||
}
|
||||
}
|
||||
|
||||
static int of_check_msi_parent(struct device_node *dev_node, struct device_node **msi_node)
|
||||
static int of_check_msi_parent(struct device_node *dev_node, struct device_node **msi_node,
|
||||
struct of_phandle_args *msi_spec)
|
||||
{
|
||||
struct of_phandle_args msi_spec;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* An msi-parent phandle with a missing or == 0 #msi-cells
|
||||
* property identifies a 1:1 ID translation mapping.
|
||||
*
|
||||
* Set the msi controller node if the firmware matches this
|
||||
* condition.
|
||||
* @msi_spec keeps a reference to the target node whenever the
|
||||
* phandle parses, -EINVAL included, and the caller releases it.
|
||||
*/
|
||||
ret = of_parse_phandle_with_optional_args(dev_node, "msi-parent", "#msi-cells",
|
||||
0, &msi_spec);
|
||||
0, msi_spec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((*msi_node && *msi_node != msi_spec.np) || msi_spec.args_count != 0)
|
||||
ret = -EINVAL;
|
||||
if ((*msi_node && *msi_node != msi_spec->np) || msi_spec->args_count != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ret && !*msi_node) {
|
||||
/* Return with a node reference held */
|
||||
*msi_node = msi_spec.np;
|
||||
return 0;
|
||||
}
|
||||
of_node_put(msi_spec.np);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -806,7 +799,9 @@ static int of_check_msi_parent(struct device_node *dev_node, struct device_node
|
|||
* @id_in: Device ID.
|
||||
*
|
||||
* Walk up the device hierarchy looking for devices with a "msi-map"
|
||||
* or "msi-parent" property. If found, apply the mapping to @id_in.
|
||||
* or "msi-parent" property. If found, apply the mapping to @id_in. With
|
||||
* @msi_np non-NULL, a device declaring an msi-parent ends the walk, usable
|
||||
* or not.
|
||||
*
|
||||
* Returns: The mapped MSI id.
|
||||
*/
|
||||
|
|
@ -821,6 +816,7 @@ u32 of_msi_xlate(struct device *dev, struct device_node **msi_np, u32 id_in)
|
|||
*/
|
||||
for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) {
|
||||
struct of_phandle_args msi_spec = {};
|
||||
int ret;
|
||||
|
||||
if (!of_map_msi_id(parent_dev->of_node, id_in, msi_np, &msi_spec)) {
|
||||
if (msi_spec.np) {
|
||||
|
|
@ -835,8 +831,17 @@ u32 of_msi_xlate(struct device *dev, struct device_node **msi_np, u32 id_in)
|
|||
break;
|
||||
}
|
||||
/* -ENODEV: msi-map absent → check for msi-parent */
|
||||
if (msi_np && !of_check_msi_parent(parent_dev->of_node, msi_np))
|
||||
if (!msi_np)
|
||||
continue;
|
||||
|
||||
ret = of_check_msi_parent(parent_dev->of_node, msi_np, &msi_spec);
|
||||
if (msi_spec.np) {
|
||||
/* A declared msi-parent names the controller, usable or not */
|
||||
if (!ret && !*msi_np)
|
||||
*msi_np = of_node_get(msi_spec.np);
|
||||
of_node_put(msi_spec.np);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return id_out;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user