lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 23 May 2019 01:20:42 +0000
From:   Ioana Ciornei <ioana.ciornei@....com>
To:     "linux@...linux.org.uk" <linux@...linux.org.uk>,
        "f.fainelli@...il.com" <f.fainelli@...il.com>,
        "andrew@...n.ch" <andrew@...n.ch>,
        "hkallweit1@...il.com" <hkallweit1@...il.com>,
        "maxime.chevallier@...tlin.com" <maxime.chevallier@...tlin.com>,
        "olteanv@...il.com" <olteanv@...il.com>
CC:     "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
        "davem@...emloft.net" <davem@...emloft.net>,
        Ioana Ciornei <ioana.ciornei@....com>
Subject: [RFC PATCH net-next 8/9] net: dsa: Use PHYLINK for the CPU/DSA ports

This completely removes the usage of PHYLIB from DSA, namely for the
aforementioned switch ports which used to drive a software PHY manually
using genphy operations.

For these ports, the newly introduced phylink_create_raw API must be
used, and the callbacks are received through a notifier block registered
per dsa_port, but otherwise the implementation is fairly
straightforward, and the handling of the regular vs raw PHYLINK
instances is common from the perspective of the driver.

What changes for drivers:

The .adjust_link callback is no longer called for the fixed-link CPU/DSA
ports and drivers must migrate to standard PHYLINK operations (e.g.
.phylink_mac_config).  The reason why we can't do anything for them is
because PHYLINK does not wrap the fixed link state behind a phydev
object, so we cannot wrap .phylink_mac_config into .adjust_link unless
we fabricate a phy_device structure.

Signed-off-by: Ioana Ciornei <ioana.ciornei@....com>
---
 include/net/dsa.h |   3 +
 net/dsa/port.c    | 137 +++++++++++++++++++++-------------------------
 2 files changed, 64 insertions(+), 76 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 685294817712..87616ff00919 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -212,6 +212,9 @@ struct dsa_port {
 	 * Original copy of the master netdev net_device_ops
 	 */
 	const struct net_device_ops *orig_ndo_ops;
+
+	/* Listener for phylink events on ports with no netdev */
+	struct notifier_block	nb;
 };
 
 struct dsa_switch {
diff --git a/net/dsa/port.c b/net/dsa/port.c
index d0f955e8b731..31bd07dd42db 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -13,6 +13,7 @@
 #include <linux/if_bridge.h>
 #include <linux/notifier.h>
 #include <linux/of_mdio.h>
+#include <linux/phylink.h>
 #include <linux/of_net.h>
 
 #include "dsa_priv.h"
@@ -511,104 +512,88 @@ void dsa_port_phylink_fixed_state(struct dsa_port *dp,
 {
 	struct dsa_switch *ds = dp->ds;
 
-	/* No need to check that this operation is valid, the callback would
-	 * not be called if it was not.
+	/* We need to check that the callback exists because phylink raw will
+	 * send PHYLINK_GET_FIXED_STATE events without an explicit register.
 	 */
-	ds->ops->phylink_fixed_state(ds, dp->index, state);
+	if (ds->ops->phylink_fixed_state)
+		ds->ops->phylink_fixed_state(ds, dp->index, state);
 }
 EXPORT_SYMBOL(dsa_port_phylink_fixed_state);
 
-static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
-{
-	struct dsa_switch *ds = dp->ds;
-	struct phy_device *phydev;
-	int port = dp->index;
-	int err = 0;
-
-	phydev = dsa_port_get_phy_device(dp);
-	if (!phydev)
-		return 0;
-
-	if (IS_ERR(phydev))
-		return PTR_ERR(phydev);
-
-	if (enable) {
-		err = genphy_config_init(phydev);
-		if (err < 0)
-			goto err_put_dev;
-
-		err = genphy_resume(phydev);
-		if (err < 0)
-			goto err_put_dev;
-
-		err = genphy_read_status(phydev);
-		if (err < 0)
-			goto err_put_dev;
-	} else {
-		err = genphy_suspend(phydev);
-		if (err < 0)
-			goto err_put_dev;
+static int dsa_cpu_port_event(struct notifier_block *nb,
+			      unsigned long event, void *ptr)
+{
+	struct phylink_notifier_info *info = ptr;
+	struct dsa_port *dp = container_of(nb, struct dsa_port, nb);
+
+	switch (event) {
+	case PHYLINK_VALIDATE:
+		dsa_port_phylink_validate(dp, info->supported, info->state);
+		break;
+	case PHYLINK_MAC_AN_RESTART:
+		dsa_port_phylink_mac_an_restart(dp);
+		break;
+	case PHYLINK_MAC_CONFIG:
+		dsa_port_phylink_mac_config(dp, info->link_an_mode,
+					    info->state);
+		break;
+	case PHYLINK_MAC_LINK_DOWN:
+		dsa_port_phylink_mac_link_down(dp, info->link_an_mode,
+					       info->interface, info->phydev);
+		break;
+	case PHYLINK_MAC_LINK_UP:
+		dsa_port_phylink_mac_link_up(dp, info->link_an_mode,
+					     info->interface, info->phydev);
+		break;
+	case PHYLINK_GET_FIXED_STATE:
+		dsa_port_phylink_fixed_state(dp, info->state);
+		break;
+	default:
+		return NOTIFY_OK;
 	}
 
-	if (ds->ops->adjust_link)
-		ds->ops->adjust_link(ds, port, phydev);
-
-	dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev));
-
-err_put_dev:
-	put_device(&phydev->mdio.dev);
-	return err;
+	return NOTIFY_DONE;
 }
 
-static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
+int dsa_port_link_register_of(struct dsa_port *dp)
 {
-	struct device_node *dn = dp->dn;
-	struct dsa_switch *ds = dp->ds;
-	struct phy_device *phydev;
-	int port = dp->index;
-	int mode;
-	int err;
+	struct device_node *port_dn = dp->dn;
+	int mode, err;
 
-	err = of_phy_register_fixed_link(dn);
-	if (err) {
-		dev_err(ds->dev,
-			"failed to register the fixed PHY of port %d\n",
-			port);
-		return err;
-	}
-
-	phydev = of_phy_find_device(dn);
-
-	mode = of_get_phy_mode(dn);
+	mode = of_get_phy_mode(port_dn);
 	if (mode < 0)
 		mode = PHY_INTERFACE_MODE_NA;
-	phydev->interface = mode;
 
-	genphy_config_init(phydev);
-	genphy_read_status(phydev);
+	dp->nb.notifier_call = dsa_cpu_port_event;
+	dp->pl = phylink_create_raw(&dp->nb, of_fwnode_handle(port_dn), mode);
+	if (IS_ERR(dp->pl)) {
+		pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
+		return PTR_ERR(dp->pl);
+	}
 
-	if (ds->ops->adjust_link)
-		ds->ops->adjust_link(ds, port, phydev);
+	err = phylink_of_phy_connect(dp->pl, port_dn, 0);
+	if (err) {
+		pr_err("could not attach to PHY: %d\n", err);
+		goto err_phy_connect;
+	}
 
-	put_device(&phydev->mdio.dev);
+	rtnl_lock();
+	phylink_start(dp->pl);
+	rtnl_unlock();
 
 	return 0;
-}
 
-int dsa_port_link_register_of(struct dsa_port *dp)
-{
-	if (of_phy_is_fixed_link(dp->dn))
-		return dsa_port_fixed_link_register_of(dp);
-	else
-		return dsa_port_setup_phy_of(dp, true);
+err_phy_connect:
+	phylink_destroy(dp->pl);
+	return err;
 }
 
 void dsa_port_link_unregister_of(struct dsa_port *dp)
 {
-	if (of_phy_is_fixed_link(dp->dn))
-		of_phy_deregister_fixed_link(dp->dn);
-	else
-		dsa_port_setup_phy_of(dp, false);
+	rtnl_lock();
+	phylink_disconnect_phy(dp->pl);
+	rtnl_unlock();
+	phylink_destroy(dp->pl);
 }
 
 int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
-- 
2.21.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ