[PATCH v2 1/1 net-next] net: fec: enable pause frame to improve rx prefomance for 1G network
Frank Li
lznuaa at gmail.com
Wed Jan 16 21:50:36 EST 2013
Any feedback about this patch?
best regards
Frank Li
2013/1/14 Frank Li <Frank.Li at 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 at freescale.com>
> Signed-off-by: Fugang Duan <B38611 at 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
>
>
More information about the linux-arm-kernel
mailing list