Skip to content

Commit 5e28971

Browse files
committed
edtlib: fix phandle edge circular dependency
Added is_child helper to skip phandle dependency edges when the target is a descendent of the source node. This fixes a circular dependency that can occur when the dependency graph is built using tree edges (child depends on parent) and phandle edges (node - phandle target). i.e. (parent depends on child). When a parent references its own children using phandles, this circular dependency graph becomes problematic. The tree structure must always have a parent before child ordering. Since every parent already contains its child, skipping the edge addition is appropriate in this scenario. Signed-off-by: Richard Mc Sweeney <Richard.McSweeney@infineon.com>
1 parent 94c34fd commit 5e28971

File tree

1 file changed

+22
-19
lines changed
  • scripts/dts/python-devicetree/src/devicetree

1 file changed

+22
-19
lines changed

scripts/dts/python-devicetree/src/devicetree/edtlib.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,30 +2401,32 @@ def _process_properties_r(self, root_node: Node, props_node: Node) -> None:
24012401
"""
24022402
# A Node depends on any Nodes present in 'phandle',
24032403
# 'phandles', or 'phandle-array' property values.
2404+
#
2405+
# When a phandle target is a descendant of root_node, skip adding
2406+
# the dependency edge: the tree already has a child-parent edge
2407+
# for every child, so adding parent-child would create a cycle.
2408+
# The dependency is implicit because the parent already contains it.
2409+
2410+
def is_child_node(child_node):
2411+
while child_node is not None:
2412+
if root_node is child_node:
2413+
return True
2414+
child_node = child_node.parent
2415+
2416+
return False
2417+
24042418
for prop in props_node.props.values():
24052419
if prop.type == 'phandle':
2406-
# According to the DT spec, a property named 'phy-handle' is required when
2407-
# the Ethernet device is connected a physical layer device (PHY).
2408-
# But the 'phy-handle' property can point to a child node of the Ethernet device,
2409-
# so we need to check for that and not add a dependency in that case, otherwise
2410-
# we'll get a cycle in the graph.
2411-
if prop.name == "phy-handle":
2412-
def _is_child(parent_node: Node, child_node: Optional[Node]) -> bool:
2413-
if child_node is None:
2414-
return False
2415-
if parent_node is child_node:
2416-
return True
2417-
return _is_child(parent_node, child_node.parent)
2418-
if TYPE_CHECKING:
2419-
assert isinstance(prop.val, Node)
2420-
if _is_child(props_node, prop.val):
2421-
continue
2422-
self._graph.add_edge(root_node, prop.val)
2420+
if TYPE_CHECKING:
2421+
assert isinstance(prop.val, Node)
2422+
if not is_child_node(prop.val):
2423+
self._graph.add_edge(root_node, prop.val)
24232424
elif prop.type == 'phandles':
24242425
if TYPE_CHECKING:
24252426
assert isinstance(prop.val, list)
24262427
for phandle_node in prop.val:
2427-
self._graph.add_edge(root_node, phandle_node)
2428+
if not is_child_node(phandle_node):
2429+
self._graph.add_edge(root_node, phandle_node)
24282430
elif prop.type == 'phandle-array':
24292431
if TYPE_CHECKING:
24302432
assert isinstance(prop.val, list)
@@ -2433,7 +2435,8 @@ def _is_child(parent_node: Node, child_node: Optional[Node]) -> bool:
24332435
continue
24342436
if TYPE_CHECKING:
24352437
assert isinstance(cd, ControllerAndData)
2436-
self._graph.add_edge(root_node, cd.controller)
2438+
if not is_child_node(cd.controller):
2439+
self._graph.add_edge(root_node, cd.controller)
24372440

24382441
# A Node depends on whatever supports the interrupts it
24392442
# generates.

0 commit comments

Comments
 (0)