Commit 54ce00ae authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dpaa2-mac-add-PCS-support-through-the-Lynx-module'



Ioana Ciornei says:

====================
dpaa2-mac: add PCS support through the Lynx module

This patch set aims to add PCS support in the dpaa2-eth driver by
leveraging the Lynx PCS module.

The first two patches are some missing pieces: the first one adding
support for 10GBASER in Lynx PCS while the second one adds a new
function - of_mdio_find_device - which is helpful in retrieving the PCS
represented as a mdio_device.  The final patch adds the glue logic
between phylink and the Lynx PCS module: it retrieves the PCS
represented as an mdio_device and registers it to Lynx and phylink.
From that point on, any PCS callbacks are treated by Lynx, without
dpaa2-eth interaction.

Changes in v2:
 - move put_device() after destroy - 3/3
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e2f9a8fe 94ae899b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ config FSL_DPAA2_ETH
	tristate "Freescale DPAA2 Ethernet"
	depends on FSL_MC_BUS && FSL_MC_DPIO
	select PHYLINK
	select PCS_LYNX
	help
	  This is the DPAA2 Ethernet driver supporting Freescale SoCs
	  with DPAA2 (DataPath Acceleration Architecture v2).
+88 −1
Original line number Diff line number Diff line
@@ -15,6 +15,18 @@ static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
	case DPMAC_ETH_IF_RGMII:
		*if_mode = PHY_INTERFACE_MODE_RGMII;
		break;
	case DPMAC_ETH_IF_USXGMII:
		*if_mode = PHY_INTERFACE_MODE_USXGMII;
		break;
	case DPMAC_ETH_IF_QSGMII:
		*if_mode = PHY_INTERFACE_MODE_QSGMII;
		break;
	case DPMAC_ETH_IF_SGMII:
		*if_mode = PHY_INTERFACE_MODE_SGMII;
		break;
	case DPMAC_ETH_IF_XFI:
		*if_mode = PHY_INTERFACE_MODE_10GBASER;
		break;
	default:
		return -EINVAL;
	}
@@ -67,6 +79,10 @@ static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac,
					phy_interface_t interface)
{
	switch (interface) {
	case PHY_INTERFACE_MODE_10GBASER:
	case PHY_INTERFACE_MODE_USXGMII:
	case PHY_INTERFACE_MODE_QSGMII:
	case PHY_INTERFACE_MODE_SGMII:
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
	case PHY_INTERFACE_MODE_RGMII_RXID:
@@ -95,6 +111,17 @@ static void dpaa2_mac_validate(struct phylink_config *config,
	phylink_set(mask, Asym_Pause);

	switch (state->interface) {
	case PHY_INTERFACE_MODE_NA:
	case PHY_INTERFACE_MODE_10GBASER:
	case PHY_INTERFACE_MODE_USXGMII:
		phylink_set(mask, 10000baseT_Full);
		if (state->interface == PHY_INTERFACE_MODE_10GBASER)
			break;
		phylink_set(mask, 5000baseT_Full);
		phylink_set(mask, 2500baseT_Full);
		fallthrough;
	case PHY_INTERFACE_MODE_SGMII:
	case PHY_INTERFACE_MODE_QSGMII:
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
	case PHY_INTERFACE_MODE_RGMII_RXID:
@@ -227,6 +254,52 @@ bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
	return fixed;
}

static int dpaa2_pcs_create(struct dpaa2_mac *mac,
			    struct device_node *dpmac_node, int id)
{
	struct mdio_device *mdiodev;
	struct device_node *node;

	node = of_parse_phandle(dpmac_node, "pcs-handle", 0);
	if (!node) {
		/* do not error out on old DTS files */
		netdev_warn(mac->net_dev, "pcs-handle node not found\n");
		return 0;
	}

	if (!of_device_is_available(node) ||
	    !of_device_is_available(node->parent)) {
		netdev_err(mac->net_dev, "pcs-handle node not available\n");
		return -ENODEV;
	}

	mdiodev = of_mdio_find_device(node);
	of_node_put(node);
	if (!mdiodev)
		return -EPROBE_DEFER;

	mac->pcs = lynx_pcs_create(mdiodev);
	if (!mac->pcs) {
		netdev_err(mac->net_dev, "lynx_pcs_create() failed\n");
		put_device(&mdiodev->dev);
		return -ENOMEM;
	}

	return 0;
}

static void dpaa2_pcs_destroy(struct dpaa2_mac *mac)
{
	struct lynx_pcs *pcs = mac->pcs;
	struct device *dev = &pcs->mdio->dev;

	if (pcs) {
		lynx_pcs_destroy(pcs);
		put_device(dev);
		mac->pcs = NULL;
	}
}

int dpaa2_mac_connect(struct dpaa2_mac *mac)
{
	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
@@ -278,6 +351,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
		goto err_put_node;
	}

	if (attr.link_type == DPMAC_LINK_TYPE_PHY &&
	    attr.eth_if != DPMAC_ETH_IF_RGMII) {
		err = dpaa2_pcs_create(mac, dpmac_node, attr.id);
		if (err)
			goto err_put_node;
	}

	mac->phylink_config.dev = &net_dev->dev;
	mac->phylink_config.type = PHYLINK_NETDEV;

@@ -286,10 +366,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
				 &dpaa2_mac_phylink_ops);
	if (IS_ERR(phylink)) {
		err = PTR_ERR(phylink);
		goto err_put_node;
		goto err_pcs_destroy;
	}
	mac->phylink = phylink;

	if (mac->pcs)
		phylink_set_pcs(mac->phylink, &mac->pcs->pcs);

	err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0);
	if (err) {
		netdev_err(net_dev, "phylink_of_phy_connect() = %d\n", err);
@@ -302,6 +385,8 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)

err_phylink_destroy:
	phylink_destroy(mac->phylink);
err_pcs_destroy:
	dpaa2_pcs_destroy(mac);
err_put_node:
	of_node_put(dpmac_node);
err_close_dpmac:
@@ -316,6 +401,8 @@ void dpaa2_mac_disconnect(struct dpaa2_mac *mac)

	phylink_disconnect_phy(mac->phylink);
	phylink_destroy(mac->phylink);
	dpaa2_pcs_destroy(mac);

	dpmac_close(mac->mc_io, 0, mac->mc_dev->mc_handle);
}

+2 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/phylink.h>
#include <linux/pcs-lynx.h>

#include "dpmac.h"
#include "dpmac-cmd.h"
@@ -21,6 +22,7 @@ struct dpaa2_mac {
	struct phylink *phylink;
	phy_interface_t if_mode;
	enum dpmac_link_type if_link_type;
	struct lynx_pcs *pcs;
};

bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
+6 −0
Original line number Diff line number Diff line
@@ -93,6 +93,9 @@ static void lynx_pcs_get_state(struct phylink_pcs *pcs,
	case PHY_INTERFACE_MODE_USXGMII:
		lynx_pcs_get_state_usxgmii(lynx->mdio, state);
		break;
	case PHY_INTERFACE_MODE_10GBASER:
		phylink_mii_c45_pcs_get_state(lynx->mdio, state);
		break;
	default:
		break;
	}
@@ -172,6 +175,9 @@ static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
		break;
	case PHY_INTERFACE_MODE_USXGMII:
		return lynx_pcs_config_usxgmii(lynx->mdio, mode, advertising);
	case PHY_INTERFACE_MODE_10GBASER:
		/* Nothing to do here for 10GBASER */
		break;
	default:
		return -EOPNOTSUPP;
	}
+29 −9
Original line number Diff line number Diff line
@@ -337,6 +337,29 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
}
EXPORT_SYMBOL(of_mdiobus_register);

/**
 * of_mdio_find_device - Given a device tree node, find the mdio_device
 * @np: pointer to the mdio_device's device tree node
 *
 * If successful, returns a pointer to the mdio_device with the embedded
 * struct device refcount incremented by one, or NULL on failure.
 * The caller should call put_device() on the mdio_device after its use
 */
struct mdio_device *of_mdio_find_device(struct device_node *np)
{
	struct device *d;

	if (!np)
		return NULL;

	d = bus_find_device_by_of_node(&mdio_bus_type, np);
	if (!d)
		return NULL;

	return to_mdio_device(d);
}
EXPORT_SYMBOL(of_mdio_find_device);

/**
 * of_phy_find_device - Give a PHY node, find the phy_device
 * @phy_np: Pointer to the phy's device tree node
@@ -346,19 +369,16 @@ EXPORT_SYMBOL(of_mdiobus_register);
 */
struct phy_device *of_phy_find_device(struct device_node *phy_np)
{
	struct device *d;
	struct mdio_device *mdiodev;

	if (!phy_np)
	mdiodev = of_mdio_find_device(phy_np);
	if (!mdiodev)
		return NULL;

	d = bus_find_device_by_of_node(&mdio_bus_type, phy_np);
	if (d) {
		mdiodev = to_mdio_device(d);
	if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY)
			return to_phy_device(d);
		put_device(d);
	}
		return to_phy_device(&mdiodev->dev);

	put_device(&mdiodev->dev);

	return NULL;
}
Loading