Commit 74371272 authored by Jose Abreu's avatar Jose Abreu Committed by David S. Miller
Browse files

net: stmmac: Convert to phylink and remove phylib logic



Convert everything to phylink.
Signed-off-by: default avatarJose Abreu <joabreu@synopsys.com>
Cc: Joao Pinto <jpinto@synopsys.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@st.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent eeef2f6b
...@@ -3,7 +3,6 @@ config STMMAC_ETH ...@@ -3,7 +3,6 @@ config STMMAC_ETH
tristate "STMicroelectronics 10/100/1000/EQOS Ethernet driver" tristate "STMicroelectronics 10/100/1000/EQOS Ethernet driver"
depends on HAS_IOMEM && HAS_DMA depends on HAS_IOMEM && HAS_DMA
select MII select MII
select PHYLIB
select PHYLINK select PHYLINK
select CRC32 select CRC32
imply PTP_1588_CLOCK imply PTP_1588_CLOCK
...@@ -42,7 +41,6 @@ if STMMAC_PLATFORM ...@@ -42,7 +41,6 @@ if STMMAC_PLATFORM
config DWMAC_DWC_QOS_ETH config DWMAC_DWC_QOS_ETH
tristate "Support for snps,dwc-qos-ethernet.txt DT binding." tristate "Support for snps,dwc-qos-ethernet.txt DT binding."
select PHYLIB
select CRC32 select CRC32
select MII select MII
depends on OF && HAS_DMA depends on OF && HAS_DMA
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/stmmac.h> #include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/phylink.h> #include <linux/phylink.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "common.h" #include "common.h"
...@@ -148,9 +147,7 @@ struct stmmac_priv { ...@@ -148,9 +147,7 @@ struct stmmac_priv {
/* Generic channel for NAPI */ /* Generic channel for NAPI */
struct stmmac_channel channel[STMMAC_CH_MAX]; struct stmmac_channel channel[STMMAC_CH_MAX];
bool oldlink;
int speed; int speed;
int oldduplex;
unsigned int flow_ctrl; unsigned int flow_ctrl;
unsigned int pause; unsigned int pause;
struct mii_bus *mii; struct mii_bus *mii;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/phy.h> #include <linux/phylink.h>
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -274,7 +274,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, ...@@ -274,7 +274,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd) struct ethtool_link_ksettings *cmd)
{ {
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phy = dev->phydev;
if (priv->hw->pcs & STMMAC_PCS_RGMII || if (priv->hw->pcs & STMMAC_PCS_RGMII ||
priv->hw->pcs & STMMAC_PCS_SGMII) { priv->hw->pcs & STMMAC_PCS_SGMII) {
...@@ -353,18 +352,7 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, ...@@ -353,18 +352,7 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
return 0; return 0;
} }
if (phy == NULL) { return phylink_ethtool_ksettings_get(priv->phylink, cmd);
pr_err("%s: %s: PHY is not registered\n",
__func__, dev->name);
return -ENODEV;
}
if (!netif_running(dev)) {
pr_err("%s: interface is disabled: we cannot track "
"link speed / duplex setting\n", dev->name);
return -EBUSY;
}
phy_ethtool_ksettings_get(phy, cmd);
return 0;
} }
static int static int
...@@ -372,8 +360,6 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, ...@@ -372,8 +360,6 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd) const struct ethtool_link_ksettings *cmd)
{ {
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phy = dev->phydev;
int rc;
if (priv->hw->pcs & STMMAC_PCS_RGMII || if (priv->hw->pcs & STMMAC_PCS_RGMII ||
priv->hw->pcs & STMMAC_PCS_SGMII) { priv->hw->pcs & STMMAC_PCS_SGMII) {
...@@ -397,9 +383,7 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, ...@@ -397,9 +383,7 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
return 0; return 0;
} }
rc = phy_ethtool_ksettings_set(phy, cmd); return phylink_ethtool_ksettings_set(priv->phylink, cmd);
return rc;
} }
static u32 stmmac_ethtool_getmsglevel(struct net_device *dev) static u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
...@@ -443,6 +427,13 @@ static void stmmac_ethtool_gregs(struct net_device *dev, ...@@ -443,6 +427,13 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
NUM_DWMAC1000_DMA_REGS * 4); NUM_DWMAC1000_DMA_REGS * 4);
} }
static int stmmac_nway_reset(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
return phylink_ethtool_nway_reset(priv->phylink);
}
static void static void
stmmac_get_pauseparam(struct net_device *netdev, stmmac_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause) struct ethtool_pauseparam *pause)
...@@ -450,28 +441,13 @@ stmmac_get_pauseparam(struct net_device *netdev, ...@@ -450,28 +441,13 @@ stmmac_get_pauseparam(struct net_device *netdev,
struct stmmac_priv *priv = netdev_priv(netdev); struct stmmac_priv *priv = netdev_priv(netdev);
struct rgmii_adv adv_lp; struct rgmii_adv adv_lp;
pause->rx_pause = 0;
pause->tx_pause = 0;
if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) {
pause->autoneg = 1; pause->autoneg = 1;
if (!adv_lp.pause) if (!adv_lp.pause)
return; return;
} else { } else {
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phylink_ethtool_get_pauseparam(priv->phylink, pause);
netdev->phydev->supported) ||
!linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
netdev->phydev->supported))
return;
} }
pause->autoneg = netdev->phydev->autoneg;
if (priv->flow_ctrl & FLOW_RX)
pause->rx_pause = 1;
if (priv->flow_ctrl & FLOW_TX)
pause->tx_pause = 1;
} }
static int static int
...@@ -479,39 +455,16 @@ stmmac_set_pauseparam(struct net_device *netdev, ...@@ -479,39 +455,16 @@ stmmac_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause) struct ethtool_pauseparam *pause)
{ {
struct stmmac_priv *priv = netdev_priv(netdev); struct stmmac_priv *priv = netdev_priv(netdev);
u32 tx_cnt = priv->plat->tx_queues_to_use;
struct phy_device *phy = netdev->phydev;
int new_pause = FLOW_OFF;
struct rgmii_adv adv_lp; struct rgmii_adv adv_lp;
if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) {
pause->autoneg = 1; pause->autoneg = 1;
if (!adv_lp.pause) if (!adv_lp.pause)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return 0;
} else { } else {
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, return phylink_ethtool_set_pauseparam(priv->phylink, pause);
phy->supported) ||
!linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
phy->supported))
return -EOPNOTSUPP;
} }
if (pause->rx_pause)
new_pause |= FLOW_RX;
if (pause->tx_pause)
new_pause |= FLOW_TX;
priv->flow_ctrl = new_pause;
phy->autoneg = pause->autoneg;
if (phy->autoneg) {
if (netif_running(netdev))
return phy_start_aneg(phy);
}
stmmac_flow_ctrl(priv, priv->hw, phy->duplex, priv->flow_ctrl,
priv->pause, tx_cnt);
return 0;
} }
static void stmmac_get_ethtool_stats(struct net_device *dev, static void stmmac_get_ethtool_stats(struct net_device *dev,
...@@ -549,7 +502,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, ...@@ -549,7 +502,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
} }
} }
if (priv->eee_enabled) { if (priv->eee_enabled) {
int val = phy_get_eee_err(dev->phydev); int val = phylink_get_eee_err(priv->phylink);
if (val) if (val)
priv->xstats.phy_eee_wakeup_error_n = val; priv->xstats.phy_eee_wakeup_error_n = val;
} }
...@@ -694,7 +647,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, ...@@ -694,7 +647,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev,
edata->eee_active = priv->eee_active; edata->eee_active = priv->eee_active;
edata->tx_lpi_timer = priv->tx_lpi_timer; edata->tx_lpi_timer = priv->tx_lpi_timer;
return phy_ethtool_get_eee(dev->phydev, edata); return phylink_ethtool_get_eee(priv->phylink, edata);
} }
static int stmmac_ethtool_op_set_eee(struct net_device *dev, static int stmmac_ethtool_op_set_eee(struct net_device *dev,
...@@ -715,7 +668,7 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev, ...@@ -715,7 +668,7 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
ret = phy_ethtool_set_eee(dev->phydev, edata); ret = phylink_ethtool_set_eee(priv->phylink, edata);
if (ret) if (ret)
return ret; return ret;
...@@ -892,7 +845,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = { ...@@ -892,7 +845,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
.get_regs = stmmac_ethtool_gregs, .get_regs = stmmac_ethtool_gregs,
.get_regs_len = stmmac_ethtool_get_regs_len, .get_regs_len = stmmac_ethtool_get_regs_len,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
.nway_reset = phy_ethtool_nway_reset, .nway_reset = stmmac_nway_reset,
.get_pauseparam = stmmac_get_pauseparam, .get_pauseparam = stmmac_get_pauseparam,
.set_pauseparam = stmmac_set_pauseparam, .set_pauseparam = stmmac_set_pauseparam,
.self_test = stmmac_selftest_run, .self_test = stmmac_selftest_run,
......
...@@ -328,21 +328,6 @@ static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv, u32 queue) ...@@ -328,21 +328,6 @@ static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv, u32 queue)
return dirty; return dirty;
} }
/**
* stmmac_hw_fix_mac_speed - callback for speed selection
* @priv: driver private structure
* Description: on some platforms (e.g. ST), some HW system configuration
* registers have to be set according to the link speed negotiated.
*/
static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
{
struct net_device *ndev = priv->dev;
struct phy_device *phydev = ndev->phydev;
if (likely(priv->plat->fix_mac_speed))
priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed);
}
/** /**
* stmmac_enable_eee_mode - check and enter in LPI mode * stmmac_enable_eee_mode - check and enter in LPI mode
* @priv: driver private structure * @priv: driver private structure
...@@ -406,14 +391,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t) ...@@ -406,14 +391,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
*/ */
bool stmmac_eee_init(struct stmmac_priv *priv) bool stmmac_eee_init(struct stmmac_priv *priv)
{ {
struct net_device *ndev = priv->dev; int tx_lpi_timer = priv->tx_lpi_timer;
int interface = priv->plat->interface;
bool ret = false;
if ((interface != PHY_INTERFACE_MODE_MII) &&
(interface != PHY_INTERFACE_MODE_GMII) &&
!phy_interface_mode_is_rgmii(interface))
goto out;
/* Using PCS we cannot dial with the phy registers at this stage /* Using PCS we cannot dial with the phy registers at this stage
* so we do not support extra feature like EEE. * so we do not support extra feature like EEE.
...@@ -421,52 +399,32 @@ bool stmmac_eee_init(struct stmmac_priv *priv) ...@@ -421,52 +399,32 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
if ((priv->hw->pcs == STMMAC_PCS_RGMII) || if ((priv->hw->pcs == STMMAC_PCS_RGMII) ||
(priv->hw->pcs == STMMAC_PCS_TBI) || (priv->hw->pcs == STMMAC_PCS_TBI) ||
(priv->hw->pcs == STMMAC_PCS_RTBI)) (priv->hw->pcs == STMMAC_PCS_RTBI))
goto out; return false;
/* MAC core supports the EEE feature. */
if (priv->dma_cap.eee) {
int tx_lpi_timer = priv->tx_lpi_timer;
/* Check if the PHY supports EEE */
if (phy_init_eee(ndev->phydev, 1)) {
/* To manage at run-time if the EEE cannot be supported
* anymore (for example because the lp caps have been
* changed).
* In that case the driver disable own timers.
*/
mutex_lock(&priv->lock);
if (priv->eee_active) {
netdev_dbg(priv->dev, "disable EEE\n");
del_timer_sync(&priv->eee_ctrl_timer);
stmmac_set_eee_timer(priv, priv->hw, 0,
tx_lpi_timer);
}
priv->eee_active = 0;
mutex_unlock(&priv->lock);
goto out;
}
/* Activate the EEE and start timers */
mutex_lock(&priv->lock);
if (!priv->eee_active) {
priv->eee_active = 1;
timer_setup(&priv->eee_ctrl_timer,
stmmac_eee_ctrl_timer, 0);
mod_timer(&priv->eee_ctrl_timer,
STMMAC_LPI_T(eee_timer));
stmmac_set_eee_timer(priv, priv->hw,
STMMAC_DEFAULT_LIT_LS, tx_lpi_timer);
}
/* Set HW EEE according to the speed */
stmmac_set_eee_pls(priv, priv->hw, ndev->phydev->link);
ret = true; /* Check if MAC core supports the EEE feature. */
mutex_unlock(&priv->lock); if (!priv->dma_cap.eee)
return false;
mutex_lock(&priv->lock);
netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n"); /* Check if it needs to be deactivated */
if (!priv->eee_active && priv->eee_enabled) {
netdev_dbg(priv->dev, "disable EEE\n");
del_timer_sync(&priv->eee_ctrl_timer);
stmmac_set_eee_timer(priv, priv->hw, 0, tx_lpi_timer);
return false;
} }
out:
return ret; if (priv->eee_active && !priv->eee_enabled) {
timer_setup(&priv->eee_ctrl_timer, stmmac_eee_ctrl_timer, 0);
mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
stmmac_set_eee_timer(priv, priv->hw, STMMAC_DEFAULT_LIT_LS,
tx_lpi_timer);
}
mutex_unlock(&priv->lock);
netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n");
return true;
} }
/* stmmac_get_tx_hwtstamp - get HW TX timestamps /* stmmac_get_tx_hwtstamp - get HW TX timestamps
...@@ -882,54 +840,42 @@ static int stmmac_mac_link_state(struct phylink_config *config, ...@@ -882,54 +840,42 @@ static int stmmac_mac_link_state(struct phylink_config *config,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static void stmmac_mac_config(struct net_device *dev) static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{ {
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
struct phy_device *phydev = dev->phydev;
u32 ctrl; u32 ctrl;
ctrl = readl(priv->ioaddr + MAC_CTRL_REG); ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
ctrl &= ~priv->hw->link.speed_mask;
if (phydev->speed != priv->speed) { switch (state->speed) {
ctrl &= ~priv->hw->link.speed_mask; case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
switch (phydev->speed) { break;
case SPEED_1000: case SPEED_100:
ctrl |= priv->hw->link.speed1000; ctrl |= priv->hw->link.speed100;
break; break;
case SPEED_100: case SPEED_10:
ctrl |= priv->hw->link.speed100; ctrl |= priv->hw->link.speed10;
break; break;
case SPEED_10: default:
ctrl |= priv->hw->link.speed10; return;
break;
default:
netif_warn(priv, link, priv->dev,
"broken speed: %d\n", phydev->speed);
phydev->speed = SPEED_UNKNOWN;
break;
}
if (phydev->speed != SPEED_UNKNOWN)
stmmac_hw_fix_mac_speed(priv);
priv->speed = phydev->speed;
} }
/* Now we make sure that we can be in full duplex mode. priv->speed = state->speed;
* If not, we operate in half-duplex mode. */
if (phydev->duplex != priv->oldduplex) {
if (!phydev->duplex)
ctrl &= ~priv->hw->link.duplex;
else
ctrl |= priv->hw->link.duplex;
priv->oldduplex = phydev->duplex; if (priv->plat->fix_mac_speed)
} priv->plat->fix_mac_speed(priv->plat->bsp_priv, state->speed);
if (!state->duplex)
ctrl &= ~priv->hw->link.duplex;
else
ctrl |= priv->hw->link.duplex;
/* Flow Control operation */ /* Flow Control operation */
if (phydev->pause) if (state->pause)
stmmac_mac_flow_ctrl(priv, phydev->duplex); stmmac_mac_flow_ctrl(priv, state->duplex);
writel(ctrl, priv->ioaddr + MAC_CTRL_REG); writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
} }
...@@ -939,85 +885,40 @@ static void stmmac_mac_an_restart(struct phylink_config *config) ...@@ -939,85 +885,40 @@ static void stmmac_mac_an_restart(struct phylink_config *config)
/* Not Supported */ /* Not Supported */
} }
static void stmmac_mac_link_down(struct net_device *dev, bool autoneg) static void stmmac_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{ {
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
stmmac_mac_set(priv, priv->ioaddr, false); stmmac_mac_set(priv, priv->ioaddr, false);
priv->eee_active = false;
stmmac_eee_init(priv);
stmmac_set_eee_pls(priv, priv->hw, false);
} }
static void stmmac_mac_link_up(struct net_device *dev, bool autoneg) static void stmmac_mac_link_up(struct phylink_config *config,
unsigned int mode, phy_interface_t interface,
struct phy_device *phy)
{ {
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
stmmac_mac_set(priv, priv->ioaddr, true); stmmac_mac_set(priv, priv->ioaddr, true);
if (phy) {
priv->eee_active = phy_init_eee(phy, 1) >= 0;
priv->eee_enabled = stmmac_eee_init(priv);
stmmac_set_eee_pls(priv, priv->hw, true);
}
} }
static const struct phylink_mac_ops __maybe_unused stmmac_phylink_mac_ops = { static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
.validate = stmmac_validate, .validate = stmmac_validate,
.mac_link_state = stmmac_mac_link_state, .mac_link_state = stmmac_mac_link_state,
.mac_config = NULL, /* TO BE FILLED */ .mac_config = stmmac_mac_config,
.mac_an_restart = stmmac_mac_an_restart, .mac_an_restart = stmmac_mac_an_restart,
.mac_link_down = NULL, /* TO BE FILLED */ .mac_link_down = stmmac_mac_link_down,
.mac_link_up = NULL, /* TO BE FILLED */ .mac_link_up = stmmac_mac_link_up,
}; };
/**
* stmmac_adjust_link - adjusts the link parameters
* @dev: net device structure
* Description: this is the helper called by the physical abstraction layer
* drivers to communicate the phy link status. According the speed and duplex
* this driver can invoke registered glue-logic as well.
* It also invoke the eee initialization because it could happen when switch
* on different networks (that are eee capable).
*/
static void stmmac_adjust_link(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phydev = dev->phydev;
bool new_state = false;
if (!phydev)
return;
mutex_lock(&priv->lock);
if (phydev->link) {
stmmac_mac_config(dev);
if (!priv->oldlink) {
new_state = true;
priv->oldlink = true;
}
} <