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
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).
......
......@@ -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);
}
......
......@@ -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,
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
......
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