From e7e95c900338904536f7f7af98d467118909e5eb Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Wed, 23 Sep 2020 18:41:21 +0300 Subject: [PATCH 1/3] net: pcs-lynx: add support for 10GBASER Add support in the Lynx PCS module for the 10GBASE-R mode which is only used to get the link state, since it offers a single fixed speed. Signed-off-by: Ioana Ciornei Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-lynx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index c43d976820836..62bb9272dcb26 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -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; } From b5b6775d72e8662b5ea7f892bf06db4831e2c1aa Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 23 Sep 2020 18:41:22 +0300 Subject: [PATCH 2/3] of: add of_mdio_find_device() api Add a helper function which finds the mdio_device structure given a device tree node. This is helpful for finding the PCS device based on a DTS node but managing it as a mdio_device instead of a phy_device. Signed-off-by: Russell King Signed-off-by: Ioana Ciornei Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/of/of_mdio.c | 38 +++++++++++++++++++++++++++++--------- include/linux/of_mdio.h | 6 ++++++ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index cb32d7ef49382..4daf94bb56a53 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -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); - } + if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) + return to_phy_device(&mdiodev->dev); + + put_device(&mdiodev->dev); return NULL; } diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index 1efb88d9f8928..cfe8c607a628d 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -17,6 +17,7 @@ bool of_mdiobus_child_is_phy(struct device_node *child); int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np); int devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio, struct device_node *np); +struct mdio_device *of_mdio_find_device(struct device_node *np); struct phy_device *of_phy_find_device(struct device_node *phy_np); struct phy_device * of_phy_connect(struct net_device *dev, struct device_node *phy_np, @@ -74,6 +75,11 @@ static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node * return mdiobus_register(mdio); } +static inline struct mdio_device *of_mdio_find_device(struct device_node *np) +{ + return NULL; +} + static inline struct phy_device *of_phy_find_device(struct device_node *phy_np) { return NULL; From 94ae899b20961a248693db6b284de9cf4c8cb7c3 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Wed, 23 Sep 2020 18:41:23 +0300 Subject: [PATCH 3/3] dpaa2-mac: add PCS support through the Lynx module Include PCS support in the dpaa2-eth driver by integrating it with the new Lynx PCS module. There is not much to talk about in terms of changes needed in the dpaa2-eth driver since the only steps necessary are to find the MDIO device representing the PCS, register it to the Lynx PCS module and then let phylink know if its existence also. After this, the PCS callbacks will be treated directly by Lynx, without interraction from dpaa2-eth's part. Signed-off-by: Ioana Ciornei Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/Kconfig | 1 + .../net/ethernet/freescale/dpaa2/dpaa2-mac.c | 89 ++++++++++++++++++- .../net/ethernet/freescale/dpaa2/dpaa2-mac.h | 2 + 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index feea797cde022..cfd369cf4c8c7 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -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). diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index 3ee236c5fc37c..6ff64dd1cf274 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -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); } diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h index 2130d9c7d40ea..955a52856210f 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h @@ -7,6 +7,7 @@ #include #include #include +#include #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,