[PATCH 1/2 net-next] net: fec: add napi support to improve proformance

Sascha Hauer s.hauer at pengutronix.de
Wed Jan 23 02:26:35 EST 2013


On Wed, Jan 23, 2013 at 12:12:10PM +0800, Frank Li wrote:
> Add napi support
> 
> Before this patch
> 
>  iperf -s -i 1
>  ------------------------------------------------------------
>  Server listening on TCP port 5001
>  TCP window size: 85.3 KByte (default)
>  ------------------------------------------------------------
>  [  4] local 10.192.242.153 port 5001 connected with 10.192.242.138 port 50004
>  [ ID] Interval       Transfer     Bandwidth
>  [  4]  0.0- 1.0 sec  41.2 MBytes   345 Mbits/sec
>  [  4]  1.0- 2.0 sec  43.7 MBytes   367 Mbits/sec
>  [  4]  2.0- 3.0 sec  42.8 MBytes   359 Mbits/sec
>  [  4]  3.0- 4.0 sec  43.7 MBytes   367 Mbits/sec
>  [  4]  4.0- 5.0 sec  42.7 MBytes   359 Mbits/sec
>  [  4]  5.0- 6.0 sec  43.8 MBytes   367 Mbits/sec
>  [  4]  6.0- 7.0 sec  43.0 MBytes   361 Mbits/sec
> 
> After this patch
>  [  4]  2.0- 3.0 sec  51.6 MBytes   433 Mbits/sec
>  [  4]  3.0- 4.0 sec  51.8 MBytes   435 Mbits/sec
>  [  4]  4.0- 5.0 sec  52.2 MBytes   438 Mbits/sec
>  [  4]  5.0- 6.0 sec  52.1 MBytes   437 Mbits/sec
>  [  4]  6.0- 7.0 sec  52.1 MBytes   437 Mbits/sec
>  [  4]  7.0- 8.0 sec  52.3 MBytes   439 Mbits/sec
> 
> Signed-off-by: Frank Li <Frank.Li at freescale.com>
> Signed-off-by: Fugang Duan <B38611 at freescale.com>
> ---
>  drivers/net/ethernet/freescale/fec.c |   68 ++++++++++++++++++++++++++++++---
>  drivers/net/ethernet/freescale/fec.h |    4 ++
>  2 files changed, 65 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
> index f52ba33..8fa420c 100644
> --- a/drivers/net/ethernet/freescale/fec.c
> +++ b/drivers/net/ethernet/freescale/fec.c
> @@ -67,6 +67,8 @@
>  #endif
>  
>  #define DRIVER_NAME	"fec"
> +#define FEC_NAPI_WEIGHT	64
> +#define INT32_MAX	0x7FFFFFFF
>  
>  /* Pause frame feild and FIFO threshold */
>  #define FEC_ENET_FCE	(1 << 5)
> @@ -565,6 +567,20 @@ fec_timeout(struct net_device *ndev)
>  }
>  
>  static void
> +fec_enet_rx_int_is_enabled(struct net_device *ndev, bool enabled)
> +{
> +	struct fec_enet_private *fep = netdev_priv(ndev);
> +	uint    int_events;
> +
> +	int_events = readl(fep->hwp + FEC_IMASK);
> +	if (enabled)
> +		int_events |= FEC_ENET_RXF;
> +	else
> +		int_events &= ~FEC_ENET_RXF;
> +	writel(int_events, fep->hwp + FEC_IMASK);
> +}
> +
> +static void
>  fec_enet_tx(struct net_device *ndev)
>  {
>  	struct	fec_enet_private *fep;
> @@ -656,8 +672,8 @@ fec_enet_tx(struct net_device *ndev)
>   * not been given to the system, we just set the empty indicator,
>   * effectively tossing the packet.
>   */
> -static void
> -fec_enet_rx(struct net_device *ndev)
> +static int
> +fec_enet_rx(struct net_device *ndev, int budget)
>  {
>  	struct fec_enet_private *fep = netdev_priv(ndev);
>  	const struct platform_device_id *id_entry =
> @@ -667,13 +683,12 @@ fec_enet_rx(struct net_device *ndev)
>  	struct	sk_buff	*skb;
>  	ushort	pkt_len;
>  	__u8 *data;
> +	int	pkt_received = 0;
>  
>  #ifdef CONFIG_M532x
>  	flush_cache_all();
>  #endif
>  
> -	spin_lock(&fep->hw_lock);
> -
>  	/* First, grab all of the stats for the incoming packet.
>  	 * These get messed up if we get called due to a busy condition.
>  	 */
> @@ -681,6 +696,10 @@ fec_enet_rx(struct net_device *ndev)
>  
>  	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
>  
> +		if (pkt_received >= budget)
> +			break;
> +		pkt_received++;
> +
>  		/* Since we have allocated space to hold a complete frame,
>  		 * the last indicator should be set.
>  		 */
> @@ -796,7 +815,7 @@ rx_processing_done:
>  	}
>  	fep->cur_rx = bdp;
>  
> -	spin_unlock(&fep->hw_lock);
> +	return pkt_received;
>  }
>  
>  static irqreturn_t
> @@ -805,6 +824,7 @@ fec_enet_interrupt(int irq, void *dev_id)
>  	struct net_device *ndev = dev_id;
>  	struct fec_enet_private *fep = netdev_priv(ndev);
>  	uint int_events;
> +	ulong flags;
>  	irqreturn_t ret = IRQ_NONE;
>  
>  	do {
> @@ -813,7 +833,18 @@ fec_enet_interrupt(int irq, void *dev_id)
>  
>  		if (int_events & FEC_ENET_RXF) {
>  			ret = IRQ_HANDLED;
> -			fec_enet_rx(ndev);
> +			spin_lock_irqsave(&fep->hw_lock, flags);
> +
> +			if (fep->use_napi) {
> +				/* Disable the RX interrupt */
> +				if (napi_schedule_prep(&fep->napi)) {
> +					fec_enet_rx_int_is_enabled(ndev, false);
> +					__napi_schedule(&fep->napi);
> +				}
> +			} else
> +				fec_enet_rx(ndev, INT32_MAX);
> +
> +			spin_unlock_irqrestore(&fep->hw_lock, flags);
>  		}
>  
>  		/* Transmit OK, or non-fatal error. Update the buffer
> @@ -834,7 +865,16 @@ fec_enet_interrupt(int irq, void *dev_id)
>  	return ret;
>  }
>  
> -
> +static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
> +{
> +	struct net_device *ndev = napi->dev;
> +	int pkgs = fec_enet_rx(ndev, budget);
> +	if (pkgs < budget) {
> +		napi_complete(napi);
> +		fec_enet_rx_int_is_enabled(ndev, true);
> +	}
> +	return pkgs;
> +}
>  
>  /* ------------------------------------------------------------------------- */
>  static void fec_get_mac(struct net_device *ndev)
> @@ -1392,6 +1432,9 @@ fec_enet_open(struct net_device *ndev)
>  	struct fec_enet_private *fep = netdev_priv(ndev);
>  	int ret;
>  
> +	if (fep->use_napi)
> +		napi_enable(&fep->napi);
> +
>  	/* I should reset the ring buffers here, but I don't yet know
>  	 * a simple way to do that.
>  	 */
> @@ -1604,6 +1647,11 @@ static int fec_enet_init(struct net_device *ndev)
>  	ndev->netdev_ops = &fec_netdev_ops;
>  	ndev->ethtool_ops = &fec_enet_ethtool_ops;
>  
> +	if (fep->use_napi) {
> +		fec_enet_rx_int_is_enabled(ndev, false);
> +		netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, fep->napi_weight);
> +	}
> +
>  	/* Initialize the receive buffer descriptors. */
>  	bdp = fep->rx_bd_base;
>  	for (i = 0; i < RX_RING_SIZE; i++) {
> @@ -1698,6 +1746,7 @@ fec_probe(struct platform_device *pdev)
>  	static int dev_id;
>  	struct pinctrl *pinctrl;
>  	struct regulator *reg_phy;
> +	struct device_node *np = pdev->dev.of_node;
>  
>  	of_id = of_match_device(fec_dt_ids, &pdev->dev);
>  	if (of_id)
> @@ -1811,6 +1860,11 @@ fec_probe(struct platform_device *pdev)
>  		}
>  	}
>  
> +	fep->use_napi = !of_property_read_bool(np, "disable_napi");
> +
> +	if (of_property_read_u32(np, "napi_weight", &fep->napi_weight))
> +		fep->napi_weight = FEC_NAPI_WEIGHT; /*using default value*/

This comment seems rather unnecessary. Also it should be

	/* space left and right /*

devicetree bindings should use '-' instead of '_'. The binding
Documentation should be in the patch adding the bindings. Also
make sure the devicetree parsing is outside of the path for platform
based probing.

With this particular binding I'm unsure it should exist anyway since
it's configuration rather than hardware description. The devicetree
normally is for hardware description only.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the linux-arm-kernel mailing list