mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 17:41:22 +00:00
Merge branch 'net-stmmac-Convert-to-phylink'
Jose Abreu says: ==================== net: stmmac: Convert to phylink This converts stmmac to use phylink. Besides the code redution this will allow to gain more flexibility. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
425b0fad9c
@ -3,7 +3,7 @@ config STMMAC_ETH
|
||||
tristate "STMicroelectronics 10/100/1000/EQOS Ethernet driver"
|
||||
depends on HAS_IOMEM && HAS_DMA
|
||||
select MII
|
||||
select PHYLIB
|
||||
select PHYLINK
|
||||
select CRC32
|
||||
imply PTP_1588_CLOCK
|
||||
select RESET_CONTROLLER
|
||||
@ -41,7 +41,6 @@ if STMMAC_PLATFORM
|
||||
|
||||
config DWMAC_DWC_QOS_ETH
|
||||
tristate "Support for snps,dwc-qos-ethernet.txt DT binding."
|
||||
select PHYLIB
|
||||
select CRC32
|
||||
select MII
|
||||
depends on OF && HAS_DMA
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/pci.h>
|
||||
#include "common.h"
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
@ -147,14 +147,15 @@ struct stmmac_priv {
|
||||
/* Generic channel for NAPI */
|
||||
struct stmmac_channel channel[STMMAC_CH_MAX];
|
||||
|
||||
bool oldlink;
|
||||
int speed;
|
||||
int oldduplex;
|
||||
unsigned int flow_ctrl;
|
||||
unsigned int pause;
|
||||
struct mii_bus *mii;
|
||||
int mii_irq[PHY_MAX_ADDR];
|
||||
|
||||
struct phylink_config phylink_config;
|
||||
struct phylink *phylink;
|
||||
|
||||
struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
|
||||
struct stmmac_safety_stats sstats;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
@ -274,7 +274,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phy = dev->phydev;
|
||||
|
||||
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII) {
|
||||
@ -353,18 +352,7 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (phy == NULL) {
|
||||
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;
|
||||
return phylink_ethtool_ksettings_get(priv->phylink, cmd);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -372,8 +360,6 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phy = dev->phydev;
|
||||
int rc;
|
||||
|
||||
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII) {
|
||||
@ -397,9 +383,7 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = phy_ethtool_ksettings_set(phy, cmd);
|
||||
|
||||
return rc;
|
||||
return phylink_ethtool_ksettings_set(priv->phylink, cmd);
|
||||
}
|
||||
|
||||
static u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
|
||||
@ -443,6 +427,13 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
|
||||
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
|
||||
stmmac_get_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
@ -450,28 +441,13 @@ stmmac_get_pauseparam(struct net_device *netdev,
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
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)) {
|
||||
pause->autoneg = 1;
|
||||
if (!adv_lp.pause)
|
||||
return;
|
||||
} else {
|
||||
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
netdev->phydev->supported) ||
|
||||
!linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
netdev->phydev->supported))
|
||||
return;
|
||||
phylink_ethtool_get_pauseparam(priv->phylink, pause);
|
||||
}
|
||||
|
||||
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
|
||||
@ -479,39 +455,16 @@ stmmac_set_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
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;
|
||||
|
||||
if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) {
|
||||
pause->autoneg = 1;
|
||||
if (!adv_lp.pause)
|
||||
return -EOPNOTSUPP;
|
||||
return 0;
|
||||
} else {
|
||||
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phy->supported) ||
|
||||
!linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phy->supported))
|
||||
return -EOPNOTSUPP;
|
||||
return phylink_ethtool_set_pauseparam(priv->phylink, pause);
|
||||
}
|
||||
|
||||
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,
|
||||
@ -549,7 +502,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
|
||||
}
|
||||
}
|
||||
if (priv->eee_enabled) {
|
||||
int val = phy_get_eee_err(dev->phydev);
|
||||
int val = phylink_get_eee_err(priv->phylink);
|
||||
if (val)
|
||||
priv->xstats.phy_eee_wakeup_error_n = val;
|
||||
}
|
||||
@ -694,7 +647,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev,
|
||||
edata->eee_active = priv->eee_active;
|
||||
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,
|
||||
@ -715,7 +668,7 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = phy_ethtool_set_eee(dev->phydev, edata);
|
||||
ret = phylink_ethtool_set_eee(priv->phylink, edata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -892,7 +845,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
|
||||
.get_regs = stmmac_ethtool_gregs,
|
||||
.get_regs_len = stmmac_ethtool_get_regs_len,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.nway_reset = phy_ethtool_nway_reset,
|
||||
.nway_reset = stmmac_nway_reset,
|
||||
.get_pauseparam = stmmac_get_pauseparam,
|
||||
.set_pauseparam = stmmac_set_pauseparam,
|
||||
.self_test = stmmac_selftest_run,
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <linux/seq_file.h>
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include "stmmac_ptp.h"
|
||||
#include "stmmac.h"
|
||||
@ -327,21 +328,6 @@ static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv, u32 queue)
|
||||
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
|
||||
* @priv: driver private structure
|
||||
@ -405,14 +391,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
|
||||
*/
|
||||
bool stmmac_eee_init(struct stmmac_priv *priv)
|
||||
{
|
||||
struct net_device *ndev = priv->dev;
|
||||
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;
|
||||
int tx_lpi_timer = priv->tx_lpi_timer;
|
||||
|
||||
/* Using PCS we cannot dial with the phy registers at this stage
|
||||
* so we do not support extra feature like EEE.
|
||||
@ -420,52 +399,32 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
|
||||
if ((priv->hw->pcs == STMMAC_PCS_RGMII) ||
|
||||
(priv->hw->pcs == STMMAC_PCS_TBI) ||
|
||||
(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 MAC core supports the EEE feature. */
|
||||
if (!priv->dma_cap.eee)
|
||||
return false;
|
||||
|
||||
/* 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));
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
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;
|
||||
mutex_unlock(&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
|
||||
@ -848,97 +807,118 @@ static void stmmac_mac_flow_ctrl(struct stmmac_priv *priv, u32 duplex)
|
||||
priv->pause, tx_cnt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
static void stmmac_validate(struct phylink_config *config,
|
||||
unsigned long *supported,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
bool new_state = false;
|
||||
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
|
||||
int tx_cnt = priv->plat->tx_queues_to_use;
|
||||
int max_speed = priv->plat->max_speed;
|
||||
|
||||
if (!phydev)
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
if (phydev->link) {
|
||||
u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
|
||||
|
||||
/* Now we make sure that we can be in full duplex mode.
|
||||
* If not, we operate in half-duplex mode. */
|
||||
if (phydev->duplex != priv->oldduplex) {
|
||||
new_state = true;
|
||||
if (!phydev->duplex)
|
||||
ctrl &= ~priv->hw->link.duplex;
|
||||
else
|
||||
ctrl |= priv->hw->link.duplex;
|
||||
priv->oldduplex = phydev->duplex;
|
||||
}
|
||||
/* Flow Control operation */
|
||||
if (phydev->pause)
|
||||
stmmac_mac_flow_ctrl(priv, phydev->duplex);
|
||||
|
||||
if (phydev->speed != priv->speed) {
|
||||
new_state = true;
|
||||
ctrl &= ~priv->hw->link.speed_mask;
|
||||
switch (phydev->speed) {
|
||||
case SPEED_1000:
|
||||
ctrl |= priv->hw->link.speed1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
ctrl |= priv->hw->link.speed100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
ctrl |= priv->hw->link.speed10;
|
||||
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;
|
||||
}
|
||||
|
||||
writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
|
||||
|
||||
if (!priv->oldlink) {
|
||||
new_state = true;
|
||||
priv->oldlink = true;
|
||||
}
|
||||
} else if (priv->oldlink) {
|
||||
new_state = true;
|
||||
priv->oldlink = false;
|
||||
priv->speed = SPEED_UNKNOWN;
|
||||
priv->oldduplex = DUPLEX_UNKNOWN;
|
||||
/* Cut down 1G if asked to */
|
||||
if ((max_speed > 0) && (max_speed < 1000)) {
|
||||
phylink_set(mask, 1000baseT_Full);
|
||||
phylink_set(mask, 1000baseX_Full);
|
||||
}
|
||||
|
||||
if (new_state && netif_msg_link(priv))
|
||||
phy_print_status(phydev);
|
||||
/* Half-Duplex can only work with single queue */
|
||||
if (tx_cnt > 1) {
|
||||
phylink_set(mask, 10baseT_Half);
|
||||
phylink_set(mask, 100baseT_Half);
|
||||
phylink_set(mask, 1000baseT_Half);
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
if (phydev->is_pseudo_fixed_link)
|
||||
/* Stop PHY layer to call the hook to adjust the link in case
|
||||
* of a switch is attached to the stmmac driver.
|
||||
*/
|
||||
phydev->irq = PHY_IGNORE_INTERRUPT;
|
||||
else
|
||||
/* At this stage, init the EEE if supported.
|
||||
* Never called in case of fixed_link.
|
||||
*/
|
||||
priv->eee_enabled = stmmac_eee_init(priv);
|
||||
bitmap_andnot(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
bitmap_andnot(state->advertising, state->advertising, mask,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
}
|
||||
|
||||
static int stmmac_mac_link_state(struct phylink_config *config,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
|
||||
ctrl &= ~priv->hw->link.speed_mask;
|
||||
|
||||
switch (state->speed) {
|
||||
case SPEED_1000:
|
||||
ctrl |= priv->hw->link.speed1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
ctrl |= priv->hw->link.speed100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
ctrl |= priv->hw->link.speed10;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
priv->speed = state->speed;
|
||||
|
||||
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 */
|
||||
if (state->pause)
|
||||
stmmac_mac_flow_ctrl(priv, state->duplex);
|
||||
|
||||
writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
|
||||
}
|
||||
|
||||
static void stmmac_mac_an_restart(struct phylink_config *config)
|
||||
{
|
||||
/* Not Supported */
|
||||
}
|
||||
|
||||
static void stmmac_mac_link_down(struct phylink_config *config,
|
||||
unsigned int mode, phy_interface_t interface)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
|
||||
|
||||
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 phylink_config *config,
|
||||
unsigned int mode, phy_interface_t interface,
|
||||
struct phy_device *phy)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
|
||||
|
||||
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 stmmac_phylink_mac_ops = {
|
||||
.validate = stmmac_validate,
|
||||
.mac_link_state = stmmac_mac_link_state,
|
||||
.mac_config = stmmac_mac_config,
|
||||
.mac_an_restart = stmmac_mac_an_restart,
|
||||
.mac_link_down = stmmac_mac_link_down,
|
||||
.mac_link_up = stmmac_mac_link_up,
|
||||
};
|
||||
|
||||
/**
|
||||
* stmmac_check_pcs_mode - verify if RGMII/SGMII is supported
|
||||
* @priv: driver private structure
|
||||
@ -975,79 +955,44 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
|
||||
static int stmmac_init_phy(struct net_device *dev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
u32 tx_cnt = priv->plat->tx_queues_to_use;
|
||||
struct phy_device *phydev;
|
||||
char phy_id_fmt[MII_BUS_ID_SIZE + 3];
|
||||
char bus_id[MII_BUS_ID_SIZE];
|
||||
int interface = priv->plat->interface;
|
||||
int max_speed = priv->plat->max_speed;
|
||||
priv->oldlink = false;
|
||||
priv->speed = SPEED_UNKNOWN;
|
||||
priv->oldduplex = DUPLEX_UNKNOWN;
|
||||
struct device_node *node;
|
||||
int ret;
|
||||
|
||||
if (priv->plat->phy_node) {
|
||||
phydev = of_phy_connect(dev, priv->plat->phy_node,
|
||||
&stmmac_adjust_link, 0, interface);
|
||||
node = priv->plat->phy_node;
|
||||
|
||||
if (node) {
|
||||
ret = phylink_of_phy_connect(priv->phylink, node, 0);
|
||||
} else {
|
||||
snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
|
||||
priv->plat->bus_id);
|
||||
int addr = priv->plat->phy_addr;
|
||||
struct phy_device *phydev;
|
||||
|
||||
snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
|
||||
priv->plat->phy_addr);
|
||||
netdev_dbg(priv->dev, "%s: trying to attach to %s\n", __func__,
|
||||
phy_id_fmt);
|
||||
|
||||
phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
|
||||
interface);
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
netdev_err(priv->dev, "Could not attach to PHY\n");
|
||||
if (!phydev)
|
||||
phydev = mdiobus_get_phy(priv->mii, addr);
|
||||
if (!phydev) {
|
||||
netdev_err(priv->dev, "no phy at addr %d\n", addr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return PTR_ERR(phydev);
|
||||
ret = phylink_connect_phy(priv->phylink, phydev);
|
||||
}
|
||||
|
||||
/* Stop Advertising 1000BASE Capability if interface is not GMII */
|
||||
if ((interface == PHY_INTERFACE_MODE_MII) ||
|
||||
(interface == PHY_INTERFACE_MODE_RMII) ||
|
||||
(max_speed < 1000 && max_speed > 0))
|
||||
phy_set_max_speed(phydev, SPEED_100);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Half-duplex mode not supported with multiqueue
|
||||
* half-duplex can only works with single queue
|
||||
*/
|
||||
if (tx_cnt > 1) {
|
||||
phy_remove_link_mode(phydev,
|
||||
ETHTOOL_LINK_MODE_10baseT_Half_BIT);
|
||||
phy_remove_link_mode(phydev,
|
||||
ETHTOOL_LINK_MODE_100baseT_Half_BIT);
|
||||
phy_remove_link_mode(phydev,
|
||||
ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
|
||||
}
|
||||
static int stmmac_phy_setup(struct stmmac_priv *priv)
|
||||
{
|
||||
struct device_node *node = priv->plat->phy_node;
|
||||
int mode = priv->plat->interface;
|
||||
struct phylink *phylink;
|
||||
|
||||
/*
|
||||
* Broken HW is sometimes missing the pull-up resistor on the
|
||||
* MDIO line, which results in reads to non-existent devices returning
|
||||
* 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
|
||||
* device as well.
|
||||
* Note: phydev->phy_id is the result of reading the UID PHY registers.
|
||||
*/
|
||||
if (!priv->plat->phy_node && phydev->phy_id == 0) {
|
||||
phy_disconnect(phydev);
|
||||
return -ENODEV;
|
||||
}
|
||||
priv->phylink_config.dev = &priv->dev->dev;
|
||||
priv->phylink_config.type = PHYLINK_NETDEV;
|
||||
|
||||
/* stmmac_adjust_link will change this to PHY_IGNORE_INTERRUPT to avoid
|
||||
* subsequent PHY polling, make sure we force a link transition if
|
||||
* we have a UP/DOWN/UP transition
|
||||
*/
|
||||
if (phydev->is_pseudo_fixed_link)
|
||||
phydev->irq = PHY_POLL;
|
||||
phylink = phylink_create(&priv->phylink_config, of_fwnode_handle(node),
|
||||
mode, &stmmac_phylink_mac_ops);
|
||||
if (IS_ERR(phylink))
|
||||
return PTR_ERR(phylink);
|
||||
|
||||
phy_attached_info(phydev);
|
||||
priv->phylink = phylink;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2660,8 +2605,7 @@ static int stmmac_open(struct net_device *dev)
|
||||
|
||||
stmmac_init_tx_coalesce(priv);
|
||||
|
||||
if (dev->phydev)
|
||||
phy_start(dev->phydev);
|
||||
phylink_start(priv->phylink);
|
||||
|
||||
/* Request the IRQ lines */
|
||||
ret = request_irq(dev->irq, stmmac_interrupt,
|
||||
@ -2708,8 +2652,7 @@ lpiirq_error:
|
||||
wolirq_error:
|
||||
free_irq(dev->irq, dev);
|
||||
irq_error:
|
||||
if (dev->phydev)
|
||||
phy_stop(dev->phydev);
|
||||
phylink_stop(priv->phylink);
|
||||
|
||||
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
|
||||
del_timer_sync(&priv->tx_queue[chan].txtimer);
|
||||
@ -2718,9 +2661,7 @@ irq_error:
|
||||
init_error:
|
||||
free_dma_desc_resources(priv);
|
||||
dma_desc_error:
|
||||
if (dev->phydev)
|
||||
phy_disconnect(dev->phydev);
|
||||
|
||||
phylink_disconnect_phy(priv->phylink);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2739,10 +2680,8 @@ static int stmmac_release(struct net_device *dev)
|
||||
del_timer_sync(&priv->eee_ctrl_timer);
|
||||
|
||||
/* Stop and disconnect the PHY */
|
||||
if (dev->phydev) {
|
||||
phy_stop(dev->phydev);
|
||||
phy_disconnect(dev->phydev);
|
||||
}
|
||||
phylink_stop(priv->phylink);
|
||||
phylink_disconnect_phy(priv->phylink);
|
||||
|
||||
stmmac_stop_all_queues(priv);
|
||||
|
||||
@ -3799,6 +3738,7 @@ static void stmmac_poll_controller(struct net_device *dev)
|
||||
*/
|
||||
static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv (dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
if (!netif_running(dev))
|
||||
@ -3808,9 +3748,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
case SIOCGMIIPHY:
|
||||
case SIOCGMIIREG:
|
||||
case SIOCSMIIREG:
|
||||
if (!dev->phydev)
|
||||
return -EINVAL;
|
||||
ret = phy_mii_ioctl(dev->phydev, rq, cmd);
|
||||
ret = phylink_mii_ioctl(priv->phylink, rq, cmd);
|
||||
break;
|
||||
case SIOCSHWTSTAMP:
|
||||
ret = stmmac_hwtstamp_set(dev, rq);
|
||||
@ -4401,6 +4339,12 @@ int stmmac_dvr_probe(struct device *device,
|
||||
}
|
||||
}
|
||||
|
||||
ret = stmmac_phy_setup(priv);
|
||||
if (ret) {
|
||||
netdev_err(ndev, "failed to setup phy (%d)\n", ret);
|
||||
goto error_phy_setup;
|
||||
}
|
||||
|
||||
ret = register_netdev(ndev);
|
||||
if (ret) {
|
||||
dev_err(priv->device, "%s: ERROR %i registering the device\n",
|
||||
@ -4418,6 +4362,8 @@ int stmmac_dvr_probe(struct device *device,
|
||||
return ret;
|
||||
|
||||
error_netdev_register:
|
||||
phylink_destroy(priv->phylink);
|
||||
error_phy_setup:
|
||||
if (priv->hw->pcs != STMMAC_PCS_RGMII &&
|
||||
priv->hw->pcs != STMMAC_PCS_TBI &&
|
||||
priv->hw->pcs != STMMAC_PCS_RTBI)
|
||||
@ -4459,6 +4405,7 @@ int stmmac_dvr_remove(struct device *dev)
|
||||
stmmac_mac_set(priv, priv->ioaddr, false);
|
||||
netif_carrier_off(ndev);
|
||||
unregister_netdev(ndev);
|
||||
phylink_destroy(priv->phylink);
|
||||
if (priv->plat->stmmac_rst)
|
||||
reset_control_assert(priv->plat->stmmac_rst);
|
||||
clk_disable_unprepare(priv->plat->pclk);
|
||||
@ -4489,8 +4436,7 @@ int stmmac_suspend(struct device *dev)
|
||||
if (!ndev || !netif_running(ndev))
|
||||
return 0;
|
||||
|
||||
if (ndev->phydev)
|
||||
phy_stop(ndev->phydev);
|
||||
phylink_stop(priv->phylink);
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
@ -4515,9 +4461,7 @@ int stmmac_suspend(struct device *dev)
|
||||
}
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
priv->oldlink = false;
|
||||
priv->speed = SPEED_UNKNOWN;
|
||||
priv->oldduplex = DUPLEX_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stmmac_suspend);
|
||||
@ -4601,8 +4545,7 @@ int stmmac_resume(struct device *dev)
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
if (ndev->phydev)
|
||||
phy_start(ndev->phydev);
|
||||
phylink_start(priv->phylink);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -333,21 +333,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
|
||||
{},
|
||||
};
|
||||
|
||||
/* If phy-handle property is passed from DT, use it as the PHY */
|
||||
plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
|
||||
if (plat->phy_node)
|
||||
dev_dbg(dev, "Found phy-handle subnode\n");
|
||||
|
||||
/* If phy-handle is not specified, check if we have a fixed-phy */
|
||||
if (!plat->phy_node && of_phy_is_fixed_link(np)) {
|
||||
if ((of_phy_register_fixed_link(np) < 0))
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(dev, "Found fixed-link subnode\n");
|
||||
plat->phy_node = of_node_get(np);
|
||||
mdio = false;
|
||||
}
|
||||
|
||||
if (of_match_node(need_mdio_ids, np)) {
|
||||
plat->mdio_node = of_get_child_by_name(np, "mdio");
|
||||
} else {
|
||||
@ -396,6 +381,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
|
||||
|
||||
*mac = of_get_mac_address(np);
|
||||
plat->interface = of_get_phy_mode(np);
|
||||
plat->phy_node = np;
|
||||
|
||||
/* Get max speed of operation from device tree */
|
||||
if (of_property_read_u32(np, "max-speed", &plat->max_speed))
|
||||
@ -591,11 +577,6 @@ error_pclk_get:
|
||||
void stmmac_remove_config_dt(struct platform_device *pdev,
|
||||
struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
if (of_phy_is_fixed_link(np))
|
||||
of_phy_deregister_fixed_link(np);
|
||||
of_node_put(plat->phy_node);
|
||||
of_node_put(plat->mdio_node);
|
||||
}
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user