]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
dtoc: Warn of duplicate drivers
authorSimon Glass <sjg@chromium.org>
Wed, 3 Feb 2021 13:01:06 +0000 (06:01 -0700)
committerSimon Glass <sjg@chromium.org>
Mon, 22 Mar 2021 06:23:27 +0000 (19:23 +1300)
If drivers have the same name then we cannot distinguish them. This only
matters if the driver is actually used by dtoc, but in that case, issue
a warning.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/dtoc/src_scan.py
tools/dtoc/test_src_scan.py

index 9d161a2cbc743dc6f8ae47a0d2cacc05cbdf1ba3..fb78536e0030d4c600c70ce3a3ede724ca44c951 100644 (file)
@@ -70,6 +70,10 @@ class Driver:
         phase (str): Which phase of U-Boot to use this driver
         headers (list): List of header files needed for this driver (each a str)
             e.g. ['<asm/cpu.h>']
+        dups (list): Driver objects with the same name as this one, that were
+            found after this one
+        warn_dups (bool): True if the duplicates are not distinguisble using
+            the phase
     """
     def __init__(self, name, fname):
         self.name = name
@@ -83,6 +87,8 @@ class Driver:
         self.used = False
         self.phase = ''
         self.headers = []
+        self.dups = []
+        self.warn_dups = False
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -531,7 +537,21 @@ class Scanner:
                     self._driver_aliases[m_alias[2]] = m_alias[1]
 
         # Make the updates based on what we found
-        self._drivers.update(drivers)
+        for driver in drivers.values():
+            if driver.name in self._drivers:
+                orig = self._drivers[driver.name]
+                if self._phase:
+                    # If the original driver matches our phase, use it
+                    if orig.phase == self._phase:
+                        orig.dups.append(driver)
+                        continue
+
+                    # Otherwise use the new driver, which is assumed to match
+                else:
+                    # We have no way of distinguishing them
+                    driver.warn_dups = True
+                driver.dups.append(orig)
+            self._drivers[driver.name] = driver
         self._of_match.update(of_match)
 
     def scan_driver(self, fname):
@@ -617,6 +637,8 @@ class Scanner:
         This takes a list of nodes, finds the driver for each one and marks it
         as used.
 
+        If two used drivers have the same name, issue a warning.
+
         Args:
             nodes (list of None): Nodes that are in use
         """
@@ -626,3 +648,7 @@ class Scanner:
             driver = self._drivers.get(struct_name)
             if driver:
                 driver.used = True
+                if driver.dups and driver.warn_dups:
+                    print("Warning: Duplicate driver name '%s' (orig=%s, dups=%s)" %
+                          (driver.name, driver.fname,
+                           ', '.join([drv.fname for drv in driver.dups])))
index 245b7302fd6bd455b4e4356497ecfaabf812e4b5..598ff256a60e7c4eaca2583da30759b960202d70 100644 (file)
@@ -371,3 +371,98 @@ struct another_struct {
         with test_util.capture_sys_output() as (stdout, _):
             scan.scan_header(output)
         self.assertIn('due to unicode error', stdout.getvalue())
+
+    def setup_dup_drivers(self, name, phase=''):
+        """Set up for a duplcate test
+
+        Returns:
+            tuple:
+                Scanner to use
+                Driver record for first driver
+                Text of second driver declaration
+                Node for driver 1
+        """
+        driver1 = '''
+static const struct udevice_id test_ids[] = {
+       { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+       { }
+};
+
+U_BOOT_DRIVER(%s) = {
+       .name   = "testing",
+       .id     = UCLASS_I2C,
+       .of_match = test_ids,
+       %s
+};
+''' % (name, 'DM_PHASE(%s)' % phase if phase else '')
+        driver2 = '''
+static const struct udevice_id test_ids[] = {
+       { .compatible = "nvidia,tegra114-dvc" },
+       { }
+};
+
+U_BOOT_DRIVER(%s) = {
+       .name   = "testing",
+       .id     = UCLASS_RAM,
+       .of_match = test_ids,
+};
+''' % name
+        scan = src_scan.Scanner(None, False, None, phase)
+        scan._parse_driver('file1.c', driver1)
+        self.assertIn(name, scan._drivers)
+        drv1 = scan._drivers[name]
+
+        prop = FakeProp()
+        prop.name = 'compatible'
+        prop.value = 'nvidia,tegra114-i2c'
+        node = FakeNode()
+        node.name = 'testing'
+        node.props = {'compatible': prop}
+
+        return scan, drv1, driver2, node
+
+    def test_dup_drivers(self):
+        """Test handling of duplicate drivers"""
+        name = 'nvidia_tegra114_i2c'
+        scan, drv1, driver2, node = self.setup_dup_drivers(name)
+        self.assertEqual('', drv1.phase)
+
+        # The driver should not have a duplicate yet
+        self.assertEqual([], drv1.dups)
+
+        scan._parse_driver('file2.c', driver2)
+
+        # The first driver should now be a duplicate of the second
+        drv2 = scan._drivers[name]
+        self.assertEqual('', drv2.phase)
+        self.assertEqual(1, len(drv2.dups))
+        self.assertEqual([drv1], drv2.dups)
+
+        # There is no way to distinguish them, so we should expect a warning
+        self.assertTrue(drv2.warn_dups)
+
+        # We should see a warning
+        with test_util.capture_sys_output() as (stdout, _):
+            scan.mark_used([node])
+        self.assertEqual(
+            "Warning: Duplicate driver name 'nvidia_tegra114_i2c' (orig=file2.c, dups=file1.c)",
+            stdout.getvalue().strip())
+
+    def test_dup_drivers_phase(self):
+        """Test handling of duplicate drivers but with different phases"""
+        name = 'nvidia_tegra114_i2c'
+        scan, drv1, driver2, node = self.setup_dup_drivers(name, 'spl')
+        scan._parse_driver('file2.c', driver2)
+        self.assertEqual('spl', drv1.phase)
+
+        # The second driver should now be a duplicate of the second
+        self.assertEqual(1, len(drv1.dups))
+        drv2 = drv1.dups[0]
+
+        # The phase is different, so we should not warn of dups
+        self.assertFalse(drv1.warn_dups)
+
+        # We should not see a warning
+        with test_util.capture_sys_output() as (stdout, _):
+            scan.mark_used([node])
+        self.assertEqual('', stdout.getvalue().strip())