diff mbox series

[RFC,v1,net-next,6/7] net: dsa: felix: allow external parsing of port nodes

Message ID 20230216075321.2898003-7-colin.foster@in-advantage.com
State Superseded
Headers show
Series add support for ocelot external ports | expand

Commit Message

Colin Foster Feb. 16, 2023, 7:53 a.m. UTC
When the felix driver parses the device tree, it does so in such a way that
every node is parsed in a loop. This is done in the felix_init_structs()
function. After this is done, a separate loop will invoke
ocelot_init_port() on each port.

This causes problems if a user of the felix driver needs to retain some
information from the device tree during port initialization. A driver
might, for example, need to create call phylink_create() during
ocelot_init_port(), which requires a reference to the fwnode_handle.

Add a hook from felix into the sub-drivers, where they can optionally grab
references to the device_node when needed.

Signed-off-by: Colin Foster <colin.foster@in-advantage.com>
---
 drivers/net/dsa/ocelot/felix.c | 54 +++++++++++++++++++++++++---------
 drivers/net/dsa/ocelot/felix.h |  5 ++++
 2 files changed, 45 insertions(+), 14 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 21dcb9cadc12..b6e3a88addb8 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -1245,7 +1245,8 @@  static int felix_parse_ports_node(struct felix *felix,
 				  struct device_node *ports_node,
 				  phy_interface_t *port_phy_modes)
 {
-	struct device *dev = felix->ocelot.dev;
+	struct ocelot *ocelot = &felix->ocelot;
+	struct device *dev = ocelot->dev;
 	struct device_node *child;
 
 	for_each_available_child_of_node(ports_node, child) {
@@ -1285,6 +1286,19 @@  static int felix_parse_ports_node(struct felix *felix,
 		}
 
 		port_phy_modes[port] = phy_mode;
+
+		if (dsa_is_cpu_port(felix->ds, port) ||
+		    !felix->info->parse_port_node)
+			continue;
+
+		err = felix->info->parse_port_node(ocelot, child, phy_mode,
+						   port);
+		if (err < 0) {
+			dev_err(dev, "Unable to create etherdev for port %d\n",
+				port);
+			of_node_put(child);
+			return err;
+		}
 	}
 
 	return 0;
@@ -1396,8 +1410,7 @@  static int felix_init_structs(struct felix *felix, int num_phys_ports)
 
 	err = felix_parse_dt(felix, port_phy_modes);
 	if (err) {
-		kfree(port_phy_modes);
-		return err;
+		goto free_port_modes;
 	}
 
 	for (i = 0; i < TARGET_MAX; i++) {
@@ -1406,8 +1419,8 @@  static int felix_init_structs(struct felix *felix, int num_phys_ports)
 			dev_err(ocelot->dev,
 				"Failed to map device memory space: %pe\n",
 				target);
-			kfree(port_phy_modes);
-			return PTR_ERR(target);
+			err = PTR_ERR(target);
+			goto free_port_modes;
 		}
 
 		ocelot->targets[i] = target;
@@ -1416,8 +1429,7 @@  static int felix_init_structs(struct felix *felix, int num_phys_ports)
 	err = ocelot_regfields_init(ocelot, felix->info->regfields);
 	if (err) {
 		dev_err(ocelot->dev, "failed to init reg fields map\n");
-		kfree(port_phy_modes);
-		return err;
+		goto free_port_modes;
 	}
 
 	for (port = 0; port < num_phys_ports; port++) {
@@ -1429,8 +1441,8 @@  static int felix_init_structs(struct felix *felix, int num_phys_ports)
 		if (!ocelot_port) {
 			dev_err(ocelot->dev,
 				"failed to allocate port memory\n");
-			kfree(port_phy_modes);
-			return -ENOMEM;
+			err = -ENOMEM;
+			goto free_port_modes;
 		}
 
 		target = felix_request_port_regmap(felix, port);
@@ -1438,8 +1450,8 @@  static int felix_init_structs(struct felix *felix, int num_phys_ports)
 			dev_err(ocelot->dev,
 				"Failed to map memory space for port %d: %pe\n",
 				port, target);
-			kfree(port_phy_modes);
-			return PTR_ERR(target);
+			err = PTR_ERR(target);
+			goto free_port_modes;
 		}
 
 		ocelot_port->phy_mode = port_phy_modes[port];
@@ -1449,15 +1461,21 @@  static int felix_init_structs(struct felix *felix, int num_phys_ports)
 		ocelot->ports[port] = ocelot_port;
 	}
 
-	kfree(port_phy_modes);
-
 	if (felix->info->mdio_bus_alloc) {
 		err = felix->info->mdio_bus_alloc(ocelot);
 		if (err < 0)
-			return err;
+			goto free_port_modes;
 	}
 
+	kfree(port_phy_modes);
+
 	return 0;
+
+free_port_modes:
+	if (felix->info->phylink_of_cleanup)
+		felix->info->phylink_of_cleanup(ocelot);
+	kfree(port_phy_modes);
+	return err;
 }
 
 static void ocelot_port_purge_txtstamp_skb(struct ocelot *ocelot, int port,
@@ -1574,12 +1592,18 @@  static int felix_setup(struct dsa_switch *ds)
 	dsa_switch_for_each_available_port(dp, ds) {
 		ocelot_init_port(ocelot, dp->index);
 
+		if (felix->info->phylink_create)
+			felix->info->phylink_create(ocelot, dp->index);
+
 		/* Set the default QoS Classification based on PCP and DEI
 		 * bits of vlan tag.
 		 */
 		felix_port_qos_map_init(ocelot, dp->index);
 	}
 
+	if (felix->info->phylink_of_cleanup)
+		felix->info->phylink_of_cleanup(ocelot);
+
 	err = ocelot_devlink_sb_register(ocelot);
 	if (err)
 		goto out_deinit_ports;
@@ -1604,6 +1628,8 @@  static int felix_setup(struct dsa_switch *ds)
 	ocelot_deinit(ocelot);
 
 out_mdiobus_free:
+	if (felix->info->phylink_of_cleanup)
+		felix->info->phylink_of_cleanup(ocelot);
 	if (felix->info->mdio_bus_free)
 		felix->info->mdio_bus_free(ocelot);
 
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index d5d0b30c0b75..ffb60bcf1817 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -58,6 +58,11 @@  struct felix_info {
 	void	(*tas_guard_bands_update)(struct ocelot *ocelot, int port);
 	void	(*port_sched_speed_set)(struct ocelot *ocelot, int port,
 					u32 speed);
+	int	(*parse_port_node)(struct ocelot *ocelot,
+				   struct device_node *ports_node,
+				   phy_interface_t phy_mode, int port);
+	int	(*phylink_create)(struct ocelot *ocelot, int port);
+	void	(*phylink_of_cleanup)(struct ocelot *ocelot);
 };
 
 /* Methods for initializing the hardware resources specific to a tagging