aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorClaudiu Manoil <claudiu.manoil@freescale.com>2013-08-12 06:53:26 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-13 18:28:53 -0400
commit23402bddf9e56eecb27bbd1e5467b3b79b3dbe58 (patch)
tree26dc3784f50481c3ac8457abccd54bd7aec1748a /drivers/net/ethernet/freescale
parentebd8b934e23f45ad3fc8a5a28bc5a96741a6a106 (diff)
gianfar: Add flow control support
eTSEC has Rx and Tx flow control capabilities that may be enabled through MACCFG1[Rx_Flow, Tx_Flow] bits. These bits must not be set however when eTSEC is operated in Half-Duplex mode. Unfortunately, the driver currently sets these bits unconditionally. This patch adds the proper handling of the PAUSE frame capability register bits by implementing the ethtool -A interface. When pause autoneg is enabled, the controller uses the phy's capability to negotiate PAUSE frame settings with the link partner and reconfigures its Rx_Flow and Tx_Flow settings to match the capabilities of the link partner. If pause autoneg is off, the PAUSE frame generation may be forced manually (ethtool -A). Flow control is disabled by default now. This implementation is inspired by the tg3 driver. Signed-off-by: Lutz Jaenicke <ljaenicke@innominate.com> Signed-off-by: Claudiu Manoil <claudiu.manoil@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c51
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h10
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c74
3 files changed, 132 insertions, 3 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 3cb464780777..b2c91dcd245f 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1016,7 +1016,14 @@ static int gfar_probe(struct platform_device *ofdev)
1016 /* We need to delay at least 3 TX clocks */ 1016 /* We need to delay at least 3 TX clocks */
1017 udelay(2); 1017 udelay(2);
1018 1018
1019 tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); 1019 tempval = 0;
1020 if (!priv->pause_aneg_en && priv->tx_pause_en)
1021 tempval |= MACCFG1_TX_FLOW;
1022 if (!priv->pause_aneg_en && priv->rx_pause_en)
1023 tempval |= MACCFG1_RX_FLOW;
1024 /* the soft reset bit is not self-resetting, so we need to
1025 * clear it before resuming normal operation
1026 */
1020 gfar_write(&regs->maccfg1, tempval); 1027 gfar_write(&regs->maccfg1, tempval);
1021 1028
1022 /* Initialize MACCFG2. */ 1029 /* Initialize MACCFG2. */
@@ -1460,7 +1467,7 @@ static int init_phy(struct net_device *dev)
1460 struct gfar_private *priv = netdev_priv(dev); 1467 struct gfar_private *priv = netdev_priv(dev);
1461 uint gigabit_support = 1468 uint gigabit_support =
1462 priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? 1469 priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
1463 SUPPORTED_1000baseT_Full : 0; 1470 GFAR_SUPPORTED_GBIT : 0;
1464 phy_interface_t interface; 1471 phy_interface_t interface;
1465 1472
1466 priv->oldlink = 0; 1473 priv->oldlink = 0;
@@ -3023,6 +3030,41 @@ static irqreturn_t gfar_interrupt(int irq, void *grp_id)
3023 return IRQ_HANDLED; 3030 return IRQ_HANDLED;
3024} 3031}
3025 3032
3033static u32 gfar_get_flowctrl_cfg(struct gfar_private *priv)
3034{
3035 struct phy_device *phydev = priv->phydev;
3036 u32 val = 0;
3037
3038 if (!phydev->duplex)
3039 return val;
3040
3041 if (!priv->pause_aneg_en) {
3042 if (priv->tx_pause_en)
3043 val |= MACCFG1_TX_FLOW;
3044 if (priv->rx_pause_en)
3045 val |= MACCFG1_RX_FLOW;
3046 } else {
3047 u16 lcl_adv, rmt_adv;
3048 u8 flowctrl;
3049 /* get link partner capabilities */
3050 rmt_adv = 0;
3051 if (phydev->pause)
3052 rmt_adv = LPA_PAUSE_CAP;
3053 if (phydev->asym_pause)
3054 rmt_adv |= LPA_PAUSE_ASYM;
3055
3056 lcl_adv = mii_advertise_flowctrl(phydev->advertising);
3057
3058 flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
3059 if (flowctrl & FLOW_CTRL_TX)
3060 val |= MACCFG1_TX_FLOW;
3061 if (flowctrl & FLOW_CTRL_RX)
3062 val |= MACCFG1_RX_FLOW;
3063 }
3064
3065 return val;
3066}
3067
3026/* Called every time the controller might need to be made 3068/* Called every time the controller might need to be made
3027 * aware of new link state. The PHY code conveys this 3069 * aware of new link state. The PHY code conveys this
3028 * information through variables in the phydev structure, and this 3070 * information through variables in the phydev structure, and this
@@ -3041,6 +3083,7 @@ static void adjust_link(struct net_device *dev)
3041 lock_tx_qs(priv); 3083 lock_tx_qs(priv);
3042 3084
3043 if (phydev->link) { 3085 if (phydev->link) {
3086 u32 tempval1 = gfar_read(&regs->maccfg1);
3044 u32 tempval = gfar_read(&regs->maccfg2); 3087 u32 tempval = gfar_read(&regs->maccfg2);
3045 u32 ecntrl = gfar_read(&regs->ecntrl); 3088 u32 ecntrl = gfar_read(&regs->ecntrl);
3046 3089
@@ -3089,6 +3132,10 @@ static void adjust_link(struct net_device *dev)
3089 priv->oldspeed = phydev->speed; 3132 priv->oldspeed = phydev->speed;
3090 } 3133 }
3091 3134
3135 tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
3136 tempval1 |= gfar_get_flowctrl_cfg(priv);
3137
3138 gfar_write(&regs->maccfg1, tempval1);
3092 gfar_write(&regs->maccfg2, tempval); 3139 gfar_write(&regs->maccfg2, tempval);
3093 gfar_write(&regs->ecntrl, ecntrl); 3140 gfar_write(&regs->ecntrl, ecntrl);
3094 3141
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index ee19f2c138a6..46f56f36118f 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -146,6 +146,10 @@ extern const char gfar_driver_version[];
146 | SUPPORTED_Autoneg \ 146 | SUPPORTED_Autoneg \
147 | SUPPORTED_MII) 147 | SUPPORTED_MII)
148 148
149#define GFAR_SUPPORTED_GBIT (SUPPORTED_1000baseT_Full \
150 | SUPPORTED_Pause \
151 | SUPPORTED_Asym_Pause)
152
149/* TBI register addresses */ 153/* TBI register addresses */
150#define MII_TBICON 0x11 154#define MII_TBICON 0x11
151 155
@@ -1100,7 +1104,11 @@ struct gfar_private {
1100 /* Wake-on-LAN enabled */ 1104 /* Wake-on-LAN enabled */
1101 wol_en:1, 1105 wol_en:1,
1102 /* Enable priorty based Tx scheduling in Hw */ 1106 /* Enable priorty based Tx scheduling in Hw */
1103 prio_sched_en:1; 1107 prio_sched_en:1,
1108 /* Flow control flags */
1109 pause_aneg_en:1,
1110 tx_pause_en:1,
1111 rx_pause_en:1;
1104 1112
1105 /* The total tx and rx ring size for the enabled queues */ 1113 /* The total tx and rx ring size for the enabled queues */
1106 unsigned int total_tx_ring_size; 1114 unsigned int total_tx_ring_size;
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 21cd88124ca9..d3d7ede27ef1 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -535,6 +535,78 @@ static int gfar_sringparam(struct net_device *dev,
535 return err; 535 return err;
536} 536}
537 537
538static void gfar_gpauseparam(struct net_device *dev,
539 struct ethtool_pauseparam *epause)
540{
541 struct gfar_private *priv = netdev_priv(dev);
542
543 epause->autoneg = !!priv->pause_aneg_en;
544 epause->rx_pause = !!priv->rx_pause_en;
545 epause->tx_pause = !!priv->tx_pause_en;
546}
547
548static int gfar_spauseparam(struct net_device *dev,
549 struct ethtool_pauseparam *epause)
550{
551 struct gfar_private *priv = netdev_priv(dev);
552 struct phy_device *phydev = priv->phydev;
553 struct gfar __iomem *regs = priv->gfargrp[0].regs;
554 u32 oldadv, newadv;
555
556 if (!(phydev->supported & SUPPORTED_Pause) ||
557 (!(phydev->supported & SUPPORTED_Asym_Pause) &&
558 (epause->rx_pause != epause->tx_pause)))
559 return -EINVAL;
560
561 priv->rx_pause_en = priv->tx_pause_en = 0;
562 if (epause->rx_pause) {
563 priv->rx_pause_en = 1;
564
565 if (epause->tx_pause) {
566 priv->tx_pause_en = 1;
567 /* FLOW_CTRL_RX & TX */
568 newadv = ADVERTISED_Pause;
569 } else /* FLOW_CTLR_RX */
570 newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
571 } else if (epause->tx_pause) {
572 priv->tx_pause_en = 1;
573 /* FLOW_CTLR_TX */
574 newadv = ADVERTISED_Asym_Pause;
575 } else
576 newadv = 0;
577
578 if (epause->autoneg)
579 priv->pause_aneg_en = 1;
580 else
581 priv->pause_aneg_en = 0;
582
583 oldadv = phydev->advertising &
584 (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
585 if (oldadv != newadv) {
586 phydev->advertising &=
587 ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
588 phydev->advertising |= newadv;
589 if (phydev->autoneg)
590 /* inform link partner of our
591 * new flow ctrl settings
592 */
593 return phy_start_aneg(phydev);
594
595 if (!epause->autoneg) {
596 u32 tempval;
597 tempval = gfar_read(&regs->maccfg1);
598 tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
599 if (priv->tx_pause_en)
600 tempval |= MACCFG1_TX_FLOW;
601 if (priv->rx_pause_en)
602 tempval |= MACCFG1_RX_FLOW;
603 gfar_write(&regs->maccfg1, tempval);
604 }
605 }
606
607 return 0;
608}
609
538int gfar_set_features(struct net_device *dev, netdev_features_t features) 610int gfar_set_features(struct net_device *dev, netdev_features_t features)
539{ 611{
540 struct gfar_private *priv = netdev_priv(dev); 612 struct gfar_private *priv = netdev_priv(dev);
@@ -1806,6 +1878,8 @@ const struct ethtool_ops gfar_ethtool_ops = {
1806 .set_coalesce = gfar_scoalesce, 1878 .set_coalesce = gfar_scoalesce,
1807 .get_ringparam = gfar_gringparam, 1879 .get_ringparam = gfar_gringparam,
1808 .set_ringparam = gfar_sringparam, 1880 .set_ringparam = gfar_sringparam,
1881 .get_pauseparam = gfar_gpauseparam,
1882 .set_pauseparam = gfar_spauseparam,
1809 .get_strings = gfar_gstrings, 1883 .get_strings = gfar_gstrings,
1810 .get_sset_count = gfar_sset_count, 1884 .get_sset_count = gfar_sset_count,
1811 .get_ethtool_stats = gfar_fill_stats, 1885 .get_ethtool_stats = gfar_fill_stats,