Patchwork [v2,1/1,net-next] net: fec: enable pause frame to improve rx prefomance for 1G network

login
register
mail settings
Submitter Frank Li
Date Jan. 14, 2013, 8:49 a.m.
Message ID <1358153387-19275-1-git-send-email-Frank.Li@freescale.com>
Download mbox | patch
Permalink /patch/211736/
State Changes Requested
Delegated to: David Miller
Headers show

Comments

Frank Li - Jan. 14, 2013, 8:49 a.m.
The limition of imx6 internal bus cause fec can't achieve 1G perfomance.
There will be many packages lost because FIFO over run.

This patch enable pause frame flow control.

Before this patch
iperf -s -i 1
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[  4] local 10.192.242.153 port 5001 connected with 10.192.242.94 port 49773
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0- 1.0 sec  6.35 MBytes  53.3 Mbits/sec
[  4]  1.0- 2.0 sec  3.39 MBytes  28.5 Mbits/sec
[  4]  2.0- 3.0 sec  2.63 MBytes  22.1 Mbits/sec
[  4]  3.0- 4.0 sec  1.10 MBytes  9.23 Mbits/sec

ifconfig
   RX packets:46195 errors:1859 dropped:1 overruns:1859 frame:1859

After this patch
iperf -s -i 1

[  4] local 10.192.242.153 port 5001 connected with 10.192.242.94 port 49757
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0- 1.0 sec  49.8 MBytes   418 Mbits/sec
[  4]  1.0- 2.0 sec  50.1 MBytes   420 Mbits/sec
[  4]  2.0- 3.0 sec  47.5 MBytes   399 Mbits/sec
[  4]  3.0- 4.0 sec  45.9 MBytes   385 Mbits/sec
[  4]  4.0- 5.0 sec  44.8 MBytes   376 Mbits/sec

ifconfig
   RX packets:2348454 errors:0 dropped:16 overruns:0 frame:0

Signed-off-by: Frank Li <Frank.Li@freescale.com>
Signed-off-by: Fugang Duan <B38611@freescale.com>
---

Change from V1 to V2
 * using pause_setparam to enable/disable pause frame
 * default enable pause frame auto negotiation

 drivers/net/ethernet/freescale/fec.c |   89 +++++++++++++++++++++++++++++++++-
 drivers/net/ethernet/freescale/fec.h |    5 ++
 2 files changed, 93 insertions(+), 1 deletions(-)
Frank Li - Jan. 17, 2013, 2:50 a.m.
Any feedback about this patch?

best regards
Frank Li

2013/1/14 Frank Li <Frank.Li@freescale.com>:
> The limition of imx6 internal bus cause fec can't achieve 1G perfomance.
> There will be many packages lost because FIFO over run.
>
> This patch enable pause frame flow control.
>
> Before this patch
> iperf -s -i 1
> TCP window size: 85.3 KByte (default)
> ------------------------------------------------------------
> [  4] local 10.192.242.153 port 5001 connected with 10.192.242.94 port 49773
> [ ID] Interval       Transfer     Bandwidth
> [  4]  0.0- 1.0 sec  6.35 MBytes  53.3 Mbits/sec
> [  4]  1.0- 2.0 sec  3.39 MBytes  28.5 Mbits/sec
> [  4]  2.0- 3.0 sec  2.63 MBytes  22.1 Mbits/sec
> [  4]  3.0- 4.0 sec  1.10 MBytes  9.23 Mbits/sec
>
> ifconfig
>    RX packets:46195 errors:1859 dropped:1 overruns:1859 frame:1859
>
> After this patch
> iperf -s -i 1
>
> [  4] local 10.192.242.153 port 5001 connected with 10.192.242.94 port 49757
> [ ID] Interval       Transfer     Bandwidth
> [  4]  0.0- 1.0 sec  49.8 MBytes   418 Mbits/sec
> [  4]  1.0- 2.0 sec  50.1 MBytes   420 Mbits/sec
> [  4]  2.0- 3.0 sec  47.5 MBytes   399 Mbits/sec
> [  4]  3.0- 4.0 sec  45.9 MBytes   385 Mbits/sec
> [  4]  4.0- 5.0 sec  44.8 MBytes   376 Mbits/sec
>
> ifconfig
>    RX packets:2348454 errors:0 dropped:16 overruns:0 frame:0
>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
> Signed-off-by: Fugang Duan <B38611@freescale.com>
> ---
>
> Change from V1 to V2
>  * using pause_setparam to enable/disable pause frame
>  * default enable pause frame auto negotiation
>
>  drivers/net/ethernet/freescale/fec.c |   89 +++++++++++++++++++++++++++++++++-
>  drivers/net/ethernet/freescale/fec.h |    5 ++
>  2 files changed, 93 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
> index 6dc2094..ea30c26 100644
> --- a/drivers/net/ethernet/freescale/fec.c
> +++ b/drivers/net/ethernet/freescale/fec.c
> @@ -68,6 +68,14 @@
>
>  #define DRIVER_NAME    "fec"
>
> +/* Pause frame feild and FIFO threshold */
> +#define FEC_ENET_FCE   (1 << 5)
> +#define FEC_ENET_RSEM_V        0x84
> +#define FEC_ENET_RSFL_V        16
> +#define FEC_ENET_RAEM_V        0x8
> +#define FEC_ENET_RAFL_V        0x8
> +#define FEC_ENET_OPD_V 0xFFF0
> +
>  /* Controller is ENET-MAC */
>  #define FEC_QUIRK_ENET_MAC             (1 << 0)
>  /* Controller needs driver to swap frame */
> @@ -193,6 +201,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
>  /* Transmitter timeout */
>  #define TX_TIMEOUT (2 * HZ)
>
> +#define FEC_PAUSE_FLAG_AUTONEG 0x1
> +#define FEC_PAUSE_FLAG_ENABLE  0x2
> +
>  static int mii_cnt;
>
>  static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, int is_ex)
> @@ -470,6 +481,26 @@ fec_restart(struct net_device *ndev, int duplex)
>                 }
>  #endif
>         }
> +
> +       /* enable pause frame*/
> +       if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
> +               ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
> +                       fep->phy_dev && fep->phy_dev->pause)) {
> +
> +               rcntl |= FEC_ENET_FCE;
> +
> +               /* set FIFO thresh hold parameter to reduce overrun */
> +               writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
> +               writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
> +               writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
> +               writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
> +
> +               /* OPD */
> +               writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
> +       } else {
> +               rcntl &= ~FEC_ENET_FCE;
> +       }
> +
>         writel(rcntl, fep->hwp + FEC_R_CNTRL);
>
>         if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
> @@ -1016,8 +1047,10 @@ static int fec_enet_mii_probe(struct net_device *ndev)
>         }
>
>         /* mask with MAC supported features */
> -       if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
> +       if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
>                 phy_dev->supported &= PHY_GBIT_FEATURES;
> +               phy_dev->supported |= SUPPORTED_Pause;
> +       }
>         else
>                 phy_dev->supported &= PHY_BASIC_FEATURES;
>
> @@ -1203,7 +1236,56 @@ static int fec_enet_get_ts_info(struct net_device *ndev,
>         }
>  }
>
> +static void fec_enet_get_pauseparam(struct net_device *ndev,
> +                                   struct ethtool_pauseparam *pause)
> +{
> +       struct fec_enet_private *fep = netdev_priv(ndev);
> +
> +       pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0;
> +       pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0;
> +       pause->rx_pause = pause->tx_pause;
> +
> +}
> +
> +static int fec_enet_set_pauseparam(struct net_device *ndev,
> +                                  struct ethtool_pauseparam *pause)
> +{
> +       struct fec_enet_private *fep = netdev_priv(ndev);
> +
> +       if (pause->tx_pause != pause->rx_pause) {
> +               netdev_info(ndev,
> +                       "hardware only support enable/disable both tx and rx");
> +               return -EINVAL;
> +       }
> +
> +       fep->pause_flag = 0;
> +
> +       /* tx pause must be same as rx pause */
> +       fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
> +       fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
> +
> +       if (pause->rx_pause || pause->autoneg) {
> +               fep->phy_dev->supported |= ADVERTISED_Pause;
> +               fep->phy_dev->advertising |= ADVERTISED_Pause;
> +       } else {
> +               fep->phy_dev->supported &= ~ADVERTISED_Pause;
> +               fep->phy_dev->advertising &= ~ADVERTISED_Pause;
> +       }
> +
> +       if (pause->autoneg) {
> +               if (netif_running(ndev))
> +                       fec_stop(ndev);
> +               phy_start_aneg(fep->phy_dev);
> +       }
> +       if (netif_running(ndev))
> +               fec_restart(ndev, 0);
> +
> +       return 0;
> +}
> +
>  static const struct ethtool_ops fec_enet_ethtool_ops = {
> +       .get_pauseparam         = fec_enet_get_pauseparam,
> +       .set_pauseparam         = fec_enet_set_pauseparam,
>         .get_settings           = fec_enet_get_settings,
>         .set_settings           = fec_enet_set_settings,
>         .get_drvinfo            = fec_enet_get_drvinfo,
> @@ -1643,6 +1725,11 @@ fec_probe(struct platform_device *pdev)
>         /* setup board info structure */
>         fep = netdev_priv(ndev);
>
> +       /* default enable pause frame auto negotiation */
> +       if (pdev->id_entry &&
> +                       (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
> +               fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
> +
>         fep->hwp = ioremap(r->start, resource_size(r));
>         fep->pdev = pdev;
>         fep->dev_id = dev_id++;
> diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
> index 4862394..2ebedaf 100644
> --- a/drivers/net/ethernet/freescale/fec.h
> +++ b/drivers/net/ethernet/freescale/fec.h
> @@ -48,6 +48,10 @@
>  #define FEC_R_DES_START                0x180 /* Receive descriptor ring */
>  #define FEC_X_DES_START                0x184 /* Transmit descriptor ring */
>  #define FEC_R_BUFF_SIZE                0x188 /* Maximum receive buff size */
> +#define FEC_R_FIFO_RSFL                0x190 /* Receive FIFO section full threshold */
> +#define FEC_R_FIFO_RSEM                0x194 /* Receive FIFO section empty threshold */
> +#define FEC_R_FIFO_RAEM                0x198 /* Receive FIFO almost empty threshold */
> +#define FEC_R_FIFO_RAFL                0x19c /* Receive FIFO almost full threshold */
>  #define FEC_MIIGSK_CFGR                0x300 /* MIIGSK Configuration reg */
>  #define FEC_MIIGSK_ENR         0x308 /* MIIGSK Enable reg */
>
> @@ -243,6 +247,7 @@ struct fec_enet_private {
>         struct  completion mdio_done;
>         int     irq[FEC_IRQ_NUM];
>         int     bufdesc_ex;
> +       int     pause_flag;
>
>         struct ptp_clock *ptp_clock;
>         struct ptp_clock_info ptp_caps;
> --
> 1.7.1
>
>
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller - Jan. 17, 2013, 3:10 a.m.
From: Frank Li <lznuaa@gmail.com>
Date: Thu, 17 Jan 2013 10:50:36 +0800

> Any feedback about this patch?

Well it's full of stylistic problems.

>> +       /* enable pause frame*/
>> +       if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
>> +               ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
>> +                       fep->phy_dev && fep->phy_dev->pause)) {

This is mis-idented.

>> +
>> +               rcntl |= FEC_ENET_FCE;

That empty line before this assignment is spurious.

>> +       pause->rx_pause = pause->tx_pause;
>> +
>> +}

That empty line is unnecessary, remove it.

>> +       /* default enable pause frame auto negotiation */
>> +       if (pdev->id_entry &&
>> +                       (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))

You can't possibly tell me that this indentation looks right
to you.

You must style things like this:

	if (condition1 &&
	    condition2)

That is, you must line up the first character on the second and
subsequent lines at the first column after the openning parenthesis of
the first line.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 6dc2094..ea30c26 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -68,6 +68,14 @@ 
 
 #define DRIVER_NAME	"fec"
 
+/* Pause frame feild and FIFO threshold */
+#define FEC_ENET_FCE	(1 << 5)
+#define FEC_ENET_RSEM_V	0x84
+#define FEC_ENET_RSFL_V	16
+#define FEC_ENET_RAEM_V	0x8
+#define FEC_ENET_RAFL_V	0x8
+#define FEC_ENET_OPD_V	0xFFF0
+
 /* Controller is ENET-MAC */
 #define FEC_QUIRK_ENET_MAC		(1 << 0)
 /* Controller needs driver to swap frame */
@@ -193,6 +201,9 @@  MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
+#define FEC_PAUSE_FLAG_AUTONEG	0x1
+#define FEC_PAUSE_FLAG_ENABLE	0x2
+
 static int mii_cnt;
 
 static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, int is_ex)
@@ -470,6 +481,26 @@  fec_restart(struct net_device *ndev, int duplex)
 		}
 #endif
 	}
+
+	/* enable pause frame*/
+	if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
+		((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
+			fep->phy_dev && fep->phy_dev->pause)) {
+
+		rcntl |= FEC_ENET_FCE;
+
+		/* set FIFO thresh hold parameter to reduce overrun */
+		writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
+		writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
+		writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
+		writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
+
+		/* OPD */
+		writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
+	} else {
+		rcntl &= ~FEC_ENET_FCE;
+	}
+
 	writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
 	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
@@ -1016,8 +1047,10 @@  static int fec_enet_mii_probe(struct net_device *ndev)
 	}
 
 	/* mask with MAC supported features */
-	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
+	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
 		phy_dev->supported &= PHY_GBIT_FEATURES;
+		phy_dev->supported |= SUPPORTED_Pause;
+	}
 	else
 		phy_dev->supported &= PHY_BASIC_FEATURES;
 
@@ -1203,7 +1236,56 @@  static int fec_enet_get_ts_info(struct net_device *ndev,
 	}
 }
 
+static void fec_enet_get_pauseparam(struct net_device *ndev,
+				    struct ethtool_pauseparam *pause)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0;
+	pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0;
+	pause->rx_pause = pause->tx_pause;
+
+}
+
+static int fec_enet_set_pauseparam(struct net_device *ndev,
+				   struct ethtool_pauseparam *pause)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	if (pause->tx_pause != pause->rx_pause) {
+		netdev_info(ndev,
+			"hardware only support enable/disable both tx and rx");
+		return -EINVAL;
+	}
+
+	fep->pause_flag = 0;
+
+	/* tx pause must be same as rx pause */
+	fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
+	fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
+
+	if (pause->rx_pause || pause->autoneg) {
+		fep->phy_dev->supported |= ADVERTISED_Pause;
+		fep->phy_dev->advertising |= ADVERTISED_Pause;
+	} else {
+		fep->phy_dev->supported &= ~ADVERTISED_Pause;
+		fep->phy_dev->advertising &= ~ADVERTISED_Pause;
+	}
+
+	if (pause->autoneg) {
+		if (netif_running(ndev))
+			fec_stop(ndev);
+		phy_start_aneg(fep->phy_dev);
+	}
+	if (netif_running(ndev))
+		fec_restart(ndev, 0);
+
+	return 0;
+}
+
 static const struct ethtool_ops fec_enet_ethtool_ops = {
+	.get_pauseparam		= fec_enet_get_pauseparam,
+	.set_pauseparam		= fec_enet_set_pauseparam,
 	.get_settings		= fec_enet_get_settings,
 	.set_settings		= fec_enet_set_settings,
 	.get_drvinfo		= fec_enet_get_drvinfo,
@@ -1643,6 +1725,11 @@  fec_probe(struct platform_device *pdev)
 	/* setup board info structure */
 	fep = netdev_priv(ndev);
 
+	/* default enable pause frame auto negotiation */
+	if (pdev->id_entry &&
+			(pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
+		fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
+
 	fep->hwp = ioremap(r->start, resource_size(r));
 	fep->pdev = pdev;
 	fep->dev_id = dev_id++;
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 4862394..2ebedaf 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -48,6 +48,10 @@ 
 #define FEC_R_DES_START		0x180 /* Receive descriptor ring */
 #define FEC_X_DES_START		0x184 /* Transmit descriptor ring */
 #define FEC_R_BUFF_SIZE		0x188 /* Maximum receive buff size */
+#define FEC_R_FIFO_RSFL		0x190 /* Receive FIFO section full threshold */
+#define FEC_R_FIFO_RSEM		0x194 /* Receive FIFO section empty threshold */
+#define FEC_R_FIFO_RAEM		0x198 /* Receive FIFO almost empty threshold */
+#define FEC_R_FIFO_RAFL		0x19c /* Receive FIFO almost full threshold */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -243,6 +247,7 @@  struct fec_enet_private {
 	struct	completion mdio_done;
 	int	irq[FEC_IRQ_NUM];
 	int	bufdesc_ex;
+	int	pause_flag;
 
 	struct ptp_clock *ptp_clock;
 	struct ptp_clock_info ptp_caps;