summaryrefslogtreecommitdiff
path: root/drivers/net/ldpaa_eth/ldpaa_eth.c
diff options
context:
space:
mode:
authorPankaj Bansal <pankaj.bansal@nxp.com>2018-10-10 14:08:34 +0530
committerJoe Hershberger <joe.hershberger@ni.com>2018-10-10 12:45:28 -0500
commit1a048cd65645338069d591108031fa4ebe96d53f (patch)
tree0d4cdfa9d279c0326ac544dacfe56028be2fe095 /drivers/net/ldpaa_eth/ldpaa_eth.c
parent1ed19a1421691e0238b79f8ac14dc4a65ddd7ad0 (diff)
driver: net: fsl-mc: Add support of multiple phys for dpmac
Till now we have had cases where we had one phy device per dpmac. Now, with the upcoming products (LX2160AQDS), we have cases, where there are sometimes two phy devices for one dpmac. One phy for TX lanes and one phy for RX lanes. to handle such cases, add the support for multiple phys in ethernet driver. The ethernet link is up if all the phy devices connected to one dpmac report link up. also the link capabilities are limited by the weakest phy device. i.e. say if there are two phys for one dpmac. one operates at 10G without autoneg and other operate at 1G with autoneg. Then the ethernet interface will operate at 1G without autoneg. Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com> Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Diffstat (limited to 'drivers/net/ldpaa_eth/ldpaa_eth.c')
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_eth.c66
1 files changed, 46 insertions, 20 deletions
diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c
index 4f0b977449..fe1c03e9e4 100644
--- a/drivers/net/ldpaa_eth/ldpaa_eth.c
+++ b/drivers/net/ldpaa_eth/ldpaa_eth.c
@@ -23,26 +23,40 @@ static int init_phy(struct eth_device *dev)
struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv;
struct phy_device *phydev = NULL;
struct mii_dev *bus;
- int ret;
+ int phy_addr, phy_num;
+ int ret = 0;
bus = wriop_get_mdio(priv->dpmac_id);
if (bus == NULL)
return 0;
- phydev = phy_connect(bus, wriop_get_phy_address(priv->dpmac_id),
- dev, wriop_get_enet_if(priv->dpmac_id));
- if (!phydev) {
- printf("Failed to connect\n");
- return -1;
- }
-
- wriop_set_phy_dev(priv->dpmac_id, phydev);
+ for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
+ phy_addr = wriop_get_phy_address(priv->dpmac_id, phy_num);
+ if (phy_addr < 0)
+ continue;
- ret = phy_config(phydev);
+ phydev = phy_connect(bus, phy_addr, dev,
+ wriop_get_enet_if(priv->dpmac_id));
+ if (!phydev) {
+ printf("Failed to connect\n");
+ ret = -ENODEV;
+ break;
+ }
+ wriop_set_phy_dev(priv->dpmac_id, phy_num, phydev);
+ ret = phy_config(phydev);
+ if (ret)
+ break;
+ }
if (ret) {
- free(phydev);
- wriop_set_phy_dev(priv->dpmac_id, NULL);
+ for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
+ phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num);
+ if (!phydev)
+ continue;
+
+ free(phydev);
+ wriop_set_phy_dev(priv->dpmac_id, phy_num, NULL);
+ }
}
return ret;
@@ -390,10 +404,10 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv,
{
struct phy_device *phydev = NULL;
phy_interface_t enet_if;
+ int phy_num, phys_detected;
int err;
- /* let's start off with maximum capabilities
- */
+ /* let's start off with maximum capabilities */
enet_if = wriop_get_enet_if(priv->dpmac_id);
switch (enet_if) {
case PHY_INTERFACE_MODE_XGMII:
@@ -405,15 +419,22 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv,
}
state->up = 1;
+ phys_detected = 0;
#ifdef CONFIG_PHYLIB
state->options |= DPMAC_LINK_OPT_AUTONEG;
- phydev = wriop_get_phy_dev(priv->dpmac_id);
- if (phydev) {
+ /* start the phy devices one by one and update the dpmac state */
+ for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
+ phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num);
+ if (!phydev)
+ continue;
+
+ phys_detected++;
err = phy_startup(phydev);
if (err) {
printf("%s: Could not initialize\n", phydev->dev->name);
state->up = 0;
+ break;
}
if (phydev->link) {
state->rate = min(state->rate, (uint32_t)phydev->speed);
@@ -422,11 +443,13 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv,
if (!phydev->autoneg)
state->options &= ~DPMAC_LINK_OPT_AUTONEG;
} else {
+ /* break out of loop even if one phy is down */
state->up = 0;
+ break;
}
}
#endif
- if (!phydev)
+ if (!phys_detected)
state->options &= ~DPMAC_LINK_OPT_AUTONEG;
if (!state->up) {
@@ -568,6 +591,7 @@ static void ldpaa_eth_stop(struct eth_device *net_dev)
struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
int err = 0;
struct phy_device *phydev = NULL;
+ int phy_num;
if ((net_dev->state == ETH_STATE_PASSIVE) ||
(net_dev->state == ETH_STATE_INIT))
@@ -600,9 +624,11 @@ static void ldpaa_eth_stop(struct eth_device *net_dev)
printf("dpni_disable() failed\n");
#ifdef CONFIG_PHYLIB
- phydev = wriop_get_phy_dev(priv->dpmac_id);
- if (phydev)
- phy_shutdown(phydev);
+ for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
+ phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num);
+ if (phydev)
+ phy_shutdown(phydev);
+ }
#endif
/* Free DPBP handle and reset. */