]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: mdio: realtek-rtl9300: Refactor otto_emdio_map_ports()
authorMarkus Stockhausen <markus.stockhausen@gmx.de>
Wed, 3 Jun 2026 17:59:18 +0000 (19:59 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sat, 6 Jun 2026 01:38:55 +0000 (18:38 -0700)
This function has multiple issues:
- It uses __free low level cleanups
- It mixes "fwnode" and "of" functions

Convert this to a uniform "of" usage and manual reference counting
cleanup. With that also fix two subtle lookup bugs in the original
code.

  mdio_dn = phy_dn->parent;
  if (mdio_dn->parent != dev->of_node)
    continue;

This skips an API access and therefore misses reference counting.
Additionally in the case of a very buggy device tree, phy_dn might
be a root node. Looking up its grandparent leads to a NULL pointer
access.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://patch.msgid.link/20260603175924.123019-2-markus.stockhausen@gmx.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/mdio/mdio-realtek-rtl9300.c

index bafcd6afe6192443215e98564fb4ac69981f8630..a280363593d2b9dfa76d67c23952b4b42a7c360c 100644 (file)
@@ -427,60 +427,75 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv
  */
 static int otto_emdio_map_ports(struct device *dev)
 {
+       struct device_node *ports_dn, *phy_dn, *bus_dn, *ctrl_dn;
        struct otto_emdio_priv *priv = dev_get_drvdata(dev);
        struct device *parent = dev->parent;
-       int err;
+       u32 addr, bus, pn;
+       int err = 0;
 
-       struct fwnode_handle *ports __free(fwnode_handle) =
-               device_get_named_child_node(parent, "ethernet-ports");
-       if (!ports)
+       ports_dn = of_get_child_by_name(parent->of_node, "ethernet-ports");
+       if (!ports_dn)
                return dev_err_probe(dev, -EINVAL, "%pfwP missing ethernet-ports\n",
                                     dev_fwnode(parent));
 
-       fwnode_for_each_child_node_scoped(ports, port) {
-               struct device_node *mdio_dn;
-               u32 addr;
-               u32 bus;
-               u32 pn;
-
-               struct device_node *phy_dn __free(device_node) =
-                       of_parse_phandle(to_of_node(port), "phy-handle", 0);
+       for_each_available_child_of_node_scoped(ports_dn, port_dn) {
+               ctrl_dn = NULL;
+               bus_dn = NULL;
+               phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
                /* skip ports without phys */
                if (!phy_dn)
                        continue;
 
-               mdio_dn = phy_dn->parent;
+               bus_dn = of_get_parent(phy_dn);
+               if (!bus_dn)
+                       goto put_nodes;
+
+               ctrl_dn = of_get_parent(bus_dn);
                /* only map ports that are connected to this mdio-controller */
-               if (mdio_dn->parent != dev->of_node)
-                       continue;
+               if (ctrl_dn != dev->of_node)
+                       goto put_nodes;
 
-               err = fwnode_property_read_u32(port, "reg", &pn);
+               err = of_property_read_u32(port_dn, "reg", &pn);
                if (err)
-                       return err;
+                       goto put_nodes;
 
-               if (pn >= priv->info->num_ports)
-                       return dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn);
+               if (pn >= priv->info->num_ports) {
+                       err = dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn);
+                       goto put_nodes;
+               }
 
-               if (test_bit(pn, priv->valid_ports))
-                       return dev_err_probe(dev, -EINVAL, "duplicated port number %d\n", pn);
+               if (test_bit(pn, priv->valid_ports)) {
+                       err = dev_err_probe(dev, -EINVAL, "duplicated port number %d\n", pn);
+                       goto put_nodes;
+               }
 
-               err = of_property_read_u32(mdio_dn, "reg", &bus);
+               err = of_property_read_u32(bus_dn, "reg", &bus);
                if (err)
-                       return err;
+                       goto put_nodes;
 
-               if (bus >= priv->info->num_buses)
-                       return dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", bus);
+               if (bus >= priv->info->num_buses) {
+                       err = dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", bus);
+                       goto put_nodes;
+               }
 
                err = of_property_read_u32(phy_dn, "reg", &addr);
                if (err)
-                       return err;
+                       goto put_nodes;
 
                __set_bit(pn, priv->valid_ports);
                priv->smi_bus[pn] = bus;
                priv->smi_addr[pn] = addr;
+put_nodes:
+               of_node_put(bus_dn);
+               of_node_put(phy_dn);
+               of_node_put(ctrl_dn);
+               if (err)
+                       break;
        }
 
-       return 0;
+       of_node_put(ports_dn);
+
+       return err;
 }
 
 static int otto_emdio_probe(struct platform_device *pdev)