|
@@ -535,6 +535,78 @@ static int gfar_sringparam(struct net_device *dev,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static void gfar_gpauseparam(struct net_device *dev,
|
|
|
+ struct ethtool_pauseparam *epause)
|
|
|
+{
|
|
|
+ struct gfar_private *priv = netdev_priv(dev);
|
|
|
+
|
|
|
+ epause->autoneg = !!priv->pause_aneg_en;
|
|
|
+ epause->rx_pause = !!priv->rx_pause_en;
|
|
|
+ epause->tx_pause = !!priv->tx_pause_en;
|
|
|
+}
|
|
|
+
|
|
|
+static int gfar_spauseparam(struct net_device *dev,
|
|
|
+ struct ethtool_pauseparam *epause)
|
|
|
+{
|
|
|
+ struct gfar_private *priv = netdev_priv(dev);
|
|
|
+ struct phy_device *phydev = priv->phydev;
|
|
|
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
|
|
+ u32 oldadv, newadv;
|
|
|
+
|
|
|
+ if (!(phydev->supported & SUPPORTED_Pause) ||
|
|
|
+ (!(phydev->supported & SUPPORTED_Asym_Pause) &&
|
|
|
+ (epause->rx_pause != epause->tx_pause)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ priv->rx_pause_en = priv->tx_pause_en = 0;
|
|
|
+ if (epause->rx_pause) {
|
|
|
+ priv->rx_pause_en = 1;
|
|
|
+
|
|
|
+ if (epause->tx_pause) {
|
|
|
+ priv->tx_pause_en = 1;
|
|
|
+ /* FLOW_CTRL_RX & TX */
|
|
|
+ newadv = ADVERTISED_Pause;
|
|
|
+ } else /* FLOW_CTLR_RX */
|
|
|
+ newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
|
|
|
+ } else if (epause->tx_pause) {
|
|
|
+ priv->tx_pause_en = 1;
|
|
|
+ /* FLOW_CTLR_TX */
|
|
|
+ newadv = ADVERTISED_Asym_Pause;
|
|
|
+ } else
|
|
|
+ newadv = 0;
|
|
|
+
|
|
|
+ if (epause->autoneg)
|
|
|
+ priv->pause_aneg_en = 1;
|
|
|
+ else
|
|
|
+ priv->pause_aneg_en = 0;
|
|
|
+
|
|
|
+ oldadv = phydev->advertising &
|
|
|
+ (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
|
|
|
+ if (oldadv != newadv) {
|
|
|
+ phydev->advertising &=
|
|
|
+ ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
|
|
|
+ phydev->advertising |= newadv;
|
|
|
+ if (phydev->autoneg)
|
|
|
+ /* inform link partner of our
|
|
|
+ * new flow ctrl settings
|
|
|
+ */
|
|
|
+ return phy_start_aneg(phydev);
|
|
|
+
|
|
|
+ if (!epause->autoneg) {
|
|
|
+ u32 tempval;
|
|
|
+ tempval = gfar_read(®s->maccfg1);
|
|
|
+ tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
|
|
|
+ if (priv->tx_pause_en)
|
|
|
+ tempval |= MACCFG1_TX_FLOW;
|
|
|
+ if (priv->rx_pause_en)
|
|
|
+ tempval |= MACCFG1_RX_FLOW;
|
|
|
+ gfar_write(®s->maccfg1, tempval);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int gfar_set_features(struct net_device *dev, netdev_features_t features)
|
|
|
{
|
|
|
struct gfar_private *priv = netdev_priv(dev);
|
|
@@ -1806,6 +1878,8 @@ const struct ethtool_ops gfar_ethtool_ops = {
|
|
|
.set_coalesce = gfar_scoalesce,
|
|
|
.get_ringparam = gfar_gringparam,
|
|
|
.set_ringparam = gfar_sringparam,
|
|
|
+ .get_pauseparam = gfar_gpauseparam,
|
|
|
+ .set_pauseparam = gfar_spauseparam,
|
|
|
.get_strings = gfar_gstrings,
|
|
|
.get_sset_count = gfar_sset_count,
|
|
|
.get_ethtool_stats = gfar_fill_stats,
|