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

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
...@@ -3,6 +3,7 @@ config FSL_DPAA2_ETH ...@@ -3,6 +3,7 @@ config FSL_DPAA2_ETH
tristate "Freescale DPAA2 Ethernet" tristate "Freescale DPAA2 Ethernet"
depends on FSL_MC_BUS && FSL_MC_DPIO depends on FSL_MC_BUS && FSL_MC_DPIO
select PHYLINK select PHYLINK
select PCS_LYNX
help help
This is the DPAA2 Ethernet driver supporting Freescale SoCs This is the DPAA2 Ethernet driver supporting Freescale SoCs
with DPAA2 (DataPath Acceleration Architecture v2). with DPAA2 (DataPath Acceleration Architecture v2).
......
...@@ -15,6 +15,18 @@ static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode) ...@@ -15,6 +15,18 @@ static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
case DPMAC_ETH_IF_RGMII: case DPMAC_ETH_IF_RGMII:
*if_mode = PHY_INTERFACE_MODE_RGMII; *if_mode = PHY_INTERFACE_MODE_RGMII;
break; 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: default:
return -EINVAL; return -EINVAL;
} }
...@@ -67,6 +79,10 @@ static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac, ...@@ -67,6 +79,10 @@ static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac,
phy_interface_t interface) phy_interface_t interface)
{ {
switch (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:
case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_RXID:
...@@ -95,6 +111,17 @@ static void dpaa2_mac_validate(struct phylink_config *config, ...@@ -95,6 +111,17 @@ static void dpaa2_mac_validate(struct phylink_config *config,
phylink_set(mask, Asym_Pause); phylink_set(mask, Asym_Pause);
switch (state->interface) { 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:
case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_RXID:
...@@ -227,6 +254,52 @@ bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev, ...@@ -227,6 +254,52 @@ bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
return fixed; 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) int dpaa2_mac_connect(struct dpaa2_mac *mac)
{ {
struct fsl_mc_device *dpmac_dev = mac->mc_dev; struct fsl_mc_device *dpmac_dev = mac->mc_dev;
...@@ -278,6 +351,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac) ...@@ -278,6 +351,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
goto err_put_node; 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.dev = &net_dev->dev;
mac->phylink_config.type = PHYLINK_NETDEV; mac->phylink_config.type = PHYLINK_NETDEV;
...@@ -286,10 +366,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac) ...@@ -286,10 +366,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
&dpaa2_mac_phylink_ops); &dpaa2_mac_phylink_ops);
if (IS_ERR(phylink)) { if (IS_ERR(phylink)) {
err = PTR_ERR(phylink); err = PTR_ERR(phylink);
goto err_put_node; goto err_pcs_destroy;
} }
mac->phylink = phylink; mac->phylink = phylink;
if (mac->pcs)
phylink_set_pcs(mac->phylink, &mac->pcs->pcs);
err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0); err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0);
if (err) { if (err) {
netdev_err(net_dev, "phylink_of_phy_connect() = %d\n", err); netdev_err(net_dev, "phylink_of_phy_connect() = %d\n", err);
...@@ -302,6 +385,8 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac) ...@@ -302,6 +385,8 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
err_phylink_destroy: err_phylink_destroy:
phylink_destroy(mac->phylink); phylink_destroy(mac->phylink);
err_pcs_destroy:
dpaa2_pcs_destroy(mac);
err_put_node: err_put_node:
of_node_put(dpmac_node); of_node_put(dpmac_node);
err_close_dpmac: err_close_dpmac:
...@@ -316,6 +401,8 @@ void dpaa2_mac_disconnect(struct dpaa2_mac *mac) ...@@ -316,6 +401,8 @@ void dpaa2_mac_disconnect(struct dpaa2_mac *mac)
phylink_disconnect_phy(mac->phylink); phylink_disconnect_phy(mac->phylink);
phylink_destroy(mac->phylink); phylink_destroy(mac->phylink);
dpaa2_pcs_destroy(mac);
dpmac_close(mac->mc_io, 0, mac->mc_dev->mc_handle); dpmac_close(mac->mc_io, 0, mac->mc_dev->mc_handle);
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include <linux/of_net.h> #include <linux/of_net.h>
#include <linux/phylink.h> #include <linux/phylink.h>
#include <linux/pcs-lynx.h>
#include "dpmac.h" #include "dpmac.h"
#include "dpmac-cmd.h" #include "dpmac-cmd.h"
...@@ -21,6 +22,7 @@ struct dpaa2_mac { ...@@ -21,6 +22,7 @@ struct dpaa2_mac {
struct phylink *phylink; struct phylink *phylink;
phy_interface_t if_mode; phy_interface_t if_mode;
enum dpmac_link_type if_link_type; enum dpmac_link_type if_link_type;
struct lynx_pcs *pcs;
}; };
bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev, bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
......
...@@ -93,6 +93,9 @@ static void lynx_pcs_get_state(struct phylink_pcs *pcs, ...@@ -93,6 +93,9 @@ static void lynx_pcs_get_state(struct phylink_pcs *pcs,
case PHY_INTERFACE_MODE_USXGMII: case PHY_INTERFACE_MODE_USXGMII:
lynx_pcs_get_state_usxgmii(lynx->mdio, state); lynx_pcs_get_state_usxgmii(lynx->mdio, state);
break; break;
case PHY_INTERFACE_MODE_10GBASER:
phylink_mii_c45_pcs_get_state(lynx->mdio, state);
break;
default: default:
break; break;
} }
...@@ -172,6 +175,9 @@ static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -172,6 +175,9 @@ static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
break; break;
case PHY_INTERFACE_MODE_USXGMII: case PHY_INTERFACE_MODE_USXGMII:
return lynx_pcs_config_usxgmii(lynx->mdio, mode, advertising); return lynx_pcs_config_usxgmii(lynx->mdio, mode, advertising);
case PHY_INTERFACE_MODE_10GBASER:
/* Nothing to do here for 10GBASER */
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -337,6 +337,29 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) ...@@ -337,6 +337,29 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
} }
EXPORT_SYMBOL(of_mdiobus_register); 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 * of_phy_find_device - Give a PHY node, find the phy_device
* @phy_np: Pointer to the phy's device tree node * @phy_np: Pointer to the phy's device tree node
...@@ -346,19 +369,16 @@ EXPORT_SYMBOL(of_mdiobus_register); ...@@ -346,19 +369,16 @@ EXPORT_SYMBOL(of_mdiobus_register);
*/ */
struct phy_device *of_phy_find_device(struct device_node *phy_np) struct phy_device *of_phy_find_device(struct device_node *phy_np)
{ {
struct device *d;
struct mdio_device *mdiodev; struct mdio_device *mdiodev;
if (!phy_np) mdiodev = of_mdio_find_device(phy_np);
if (!mdiodev)
return NULL; return NULL;
d = bus_find_device_by_of_node(&mdio_bus_type, phy_np); if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY)
if (d) { return to_phy_device(&mdiodev->dev);
mdiodev = to_mdio_device(d);
if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) put_device(&mdiodev->dev);
return to_phy_device(d);
put_device(d);
}
return NULL; return NULL;
} }
......
...@@ -17,6 +17,7 @@ bool of_mdiobus_child_is_phy(struct device_node *child); ...@@ -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 of_mdiobus_register(struct mii_bus *mdio, struct device_node *np);
int devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio, int devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio,
struct device_node *np); 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_find_device(struct device_node *phy_np);
struct phy_device * struct phy_device *
of_phy_connect(struct net_device *dev, struct device_node *phy_np, 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 * ...@@ -74,6 +75,11 @@ static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *
return mdiobus_register(mdio); 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) static inline struct phy_device *of_phy_find_device(struct device_node *phy_np)
{ {
return NULL; return NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment