Skip to content

Commit cb27d92

Browse files
mathieuchopstmfabiobaltieri
authored andcommitted
scripts: build: check_init_prio: take deferred-init into account
A device with zephyr,deferred-init is initialized by the application, so we cannot check if it is initialized in "the correct order". On the other hand, a non-deferred device must not depend on a deferred-init device: this is guaranteed to be initialized out of order. Also adjust existing test cases and add a new test case to validate this behavior. Signed-off-by: Mathieu Choplain <[email protected]>
1 parent ed182a8 commit cb27d92

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

scripts/build/check_init_priorities.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@
4949
]
5050
)
5151

52+
# Deferred initialization property name.
53+
# When present, the device is not initialized during boot.
54+
# (it is evaluated as if initializing "after everything else")
55+
_DEFERRED_INIT_PROP_NAME = "zephyr,deferred-init"
56+
5257
# The offset of the init pointer in "struct device", in number of pointers.
5358
DEVICE_INIT_OFFSET = 5
5459

@@ -287,6 +292,30 @@ def _check_dep(self, dev_ord, dep_ord):
287292
self.log.info(f"Ignoring priority: {dev_node._binding.compatible}")
288293
return
289294

295+
def _deferred(node):
296+
# Even though the property is boolean, it is sometimes present
297+
# in node.props despite having value false: check for both
298+
# presence *and* value.
299+
if (p := node.props.get(_DEFERRED_INIT_PROP_NAME)) is None:
300+
return False
301+
assert isinstance(p.val, bool)
302+
return p.val
303+
304+
dev_deferred = _deferred(dev_node)
305+
dep_deferred = _deferred(dep_node)
306+
307+
# Deferred devices can depend on any device...
308+
if dev_deferred:
309+
self.log.info(f"Ignoring deferred device {dev_node.path}")
310+
return
311+
312+
# ...but non-deferred devices cannot depend on them!
313+
if dep_deferred: # we already know dev_deferred==False
314+
self._flag_error(
315+
f"Non-deferred device {dev_node.path} depends on deferred device {dep_node.path}"
316+
)
317+
return
318+
290319
dev_prio, dev_init = self._obj.devices.get(dev_ord, (None, None))
291320
dep_prio, dep_init = self._obj.devices.get(dep_ord, (None, None))
292321

scripts/build/check_init_priorities_test.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,9 @@ def test_check_dep_no_prio(self, mock_vinit):
294294

295295
validator._ord2node = {1: mock.Mock(), 2: mock.Mock()}
296296
validator._ord2node[1]._binding = None
297+
validator._ord2node[1].props = {}
297298
validator._ord2node[2]._binding = None
299+
validator._ord2node[2].props = {}
298300

299301
validator._obj.devices = {1: (10, "i1")}
300302
validator._check_dep(1, 2)
@@ -316,8 +318,10 @@ def test_check(self, mock_vinit):
316318
validator._ord2node = {1: mock.Mock(), 2: mock.Mock()}
317319
validator._ord2node[1]._binding = None
318320
validator._ord2node[1].path = "/1"
321+
validator._ord2node[1].props = {}
319322
validator._ord2node[2]._binding = None
320323
validator._ord2node[2].path = "/2"
324+
validator._ord2node[2].props = {}
321325

322326
validator._obj.devices = {1: (10, "i1"), 2: (20, "i2")}
323327

@@ -340,8 +344,10 @@ def test_check_same_prio_assert(self, mock_vinit):
340344
validator._ord2node = {1: mock.Mock(), 2: mock.Mock()}
341345
validator._ord2node[1]._binding = None
342346
validator._ord2node[1].path = "/1"
347+
validator._ord2node[1].props = {}
343348
validator._ord2node[2]._binding = None
344349
validator._ord2node[2].path = "/2"
350+
validator._ord2node[2].props = {}
345351

346352
validator._obj.devices = {1: (10, "i1"), 2: (10, "i2")}
347353

@@ -379,6 +385,34 @@ def test_check_ignored(self, mock_vinit):
379385

380386
check_init_priorities._IGNORE_COMPATIBLES = save_ignore_compatibles
381387

388+
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
389+
def test_check_deferred(self, mock_vinit):
390+
validator = check_init_priorities.Validator("", "", None, None)
391+
validator.log = mock.Mock()
392+
validator._obj = mock.Mock()
393+
validator.errors = 0
394+
395+
validator._ord2node = {1: mock.Mock(), 2: mock.Mock()}
396+
validator._ord2node[1]._binding = None
397+
validator._ord2node[1].path = "/1"
398+
validator._ord2node[1].props = {}
399+
validator._ord2node[2]._binding = None
400+
validator._ord2node[2].path = "/2"
401+
validator._ord2node[2].props = {
402+
check_init_priorities._DEFERRED_INIT_PROP_NAME: mock.Mock(val=True)
403+
}
404+
405+
validator._obj.devices = {1: (10, "i1"), 2: (5, "i2")}
406+
407+
validator._check_dep(2, 1)
408+
validator._check_dep(1, 2)
409+
410+
validator.log.info.assert_called_once_with("Ignoring deferred device /2")
411+
validator.log.error.assert_has_calls(
412+
[mock.call("Non-deferred device /1 depends on deferred device /2")]
413+
)
414+
self.assertEqual(validator.errors, 1)
415+
382416
@mock.patch("check_init_priorities.Validator._check_dep")
383417
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
384418
def test_check_edt(self, mock_vinit, mock_cd):

0 commit comments

Comments
 (0)