netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff Garzik <jgarzik@pobox.com>
To: Harald Welte <laforge@gnumonks.org>
Cc: David Miller <davem@davemloft.net>,
	netdev@oss.sgi.com, linuxppc-dev@lists.linuxppc.org
Subject: Re: [PATCH 2.6] Add NAPI support to sungem.c
Date: Tue, 14 Sep 2004 11:56:08 -0400	[thread overview]
Message-ID: <41471498.8010107@pobox.com> (raw)
In-Reply-To: <20040914153537.GE8434@sunbeam.de.gnumonks.org>

Harald Welte wrote:
> Hi Dave!
> 
> Please find the attached patch to add NAPI support to the sungem.c
> driver (I was annoyed by the fact the pktgen could kill my Powerbook).
> 
> Since this is my first hack of a network driver within at least 5 years,
> please be kind with me and point me to all the locking bugs and other
> mistakes ;)
> 
> Any comments welcome,
> 
> 	Harald
> 
> 
> 
> ------------------------------------------------------------------------
> 
> diff -Nru linux-2.6.8.1-davem269_4/drivers/net/Kconfig linux-2.6.8.1-davem269_4-sungem-napi/drivers/net/Kconfig
> --- linux-2.6.8.1-davem269_4/drivers/net/Kconfig	2004-08-14 12:56:00.000000000 +0200
> +++ linux-2.6.8.1-davem269_4-sungem-napi/drivers/net/Kconfig	2004-09-14 11:40:40.000000000 +0200
> @@ -569,6 +569,22 @@
>  	help
>  	  Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
>  	  <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
> +config SUNGEM_NAPI
> +	bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
> +	depends on SUNGEM && EXPERIMENTAL
> +	help
> +	  NAPI is a new driver API designed to reduce CPU and interrupt load
> +	  when the driver is receiving lots of packets from the card. It is
> +	  still somewhat experimental and thus not yet enabled by default.
> +
> +	  If your estimated Rx load is 10kpps or more, or if the card will be
> +	  deployed on potentially unfriendly networks (e.g. in a firewall),
> +	  then say Y here.
> +
> +	  See <file:Documentation/networking/NAPI_HOWTO.txt> for more
> +	  information.
> +
> +	  If in doubt, say N.
>  
>  config NET_VENDOR_3COM
>  	bool "3COM cards"
> --- linux-2.6.8-rc2-nfpending-tcpwin/drivers/net/sungem.c	2004-07-22 17:48:43.000000000 +0200
> +++ linux-2.6.8-rc2-nfpending-tcpwin-napi/drivers/net/sungem.c	2004-09-13 15:48:17.299866224 +0200
> @@ -5,6 +5,9 @@
>   * 
>   * Support for Apple GMAC and assorted PHYs by
>   * Benjamin Herrenscmidt (benh@kernel.crashing.org)
> + *
> + * Support for NAPI and NETPOLL 
> + * 	(C) 2004 by Harald Welte <laforge@gnumonks.org>
>   * 
>   * TODO: 
>   *  - Get rid of all those nasty mdelay's and replace them
> @@ -187,6 +190,26 @@
>  		printk(KERN_DEBUG "%s: mif interrupt\n", gp->dev->name);
>  }
>  
> +static inline void
> +gem_irq_disable(struct gem *gp)
> +{
> +	/* Make sure we won't get any more interrupts */
> +	writel(0xffffffff, gp->regs + GREG_IMASK);
> +}
> +
> +static inline void
> +gem_irq_enable(struct gem *gp, unsigned int mask)
> +{
> +	/* We don't want TXDONE, but all other interrupts */
> +	writel(mask, gp->regs + GREG_IMASK);
> +}
> +
> +static inline void
> +gem_irq_acknowledge(struct gem *gp, unsigned int mask)
> +{
> +	writel(mask, gp->regs + GREG_IACK);
> +}

PCI posting


>  static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
>  {
>  	u32 pcs_istat = readl(gp->regs + PCS_ISTAT);
> @@ -537,6 +560,7 @@
>  			printk(KERN_DEBUG "%s: no buffer for rx frame\n",
>  				gp->dev->name);
>  		gp->net_stats.rx_dropped++;
> +		gem_irq_acknowledge(gp, GREG_STAT_RXNOBUF);
>  	}
>  
>  	if (gem_status & GREG_STAT_RXTAGERR) {
> @@ -545,6 +569,7 @@
>  			printk(KERN_DEBUG "%s: corrupt rx tag framing\n",
>  				gp->dev->name);
>  		gp->net_stats.rx_errors++;
> +		gem_irq_acknowledge(gp, GREG_STAT_RXTAGERR);
>  
>  		goto do_reset;
>  	}
> @@ -596,6 +621,8 @@
>  		printk(KERN_DEBUG "%s: tx interrupt, gem_status: 0x%x\n",
>  			gp->dev->name, gem_status);
>  
> +	gem_irq_acknowledge(gp, GREG_STAT_TXALL|GREG_STAT_TXINTME);

Are these in separate functions?  If not, it's usually best to go ahead 
and ACK all the interrupts you are going to handle, in a single IO write 
(usually _before_ you handle the events).


>  	entry = gp->tx_old;
>  	limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT);
>  	while (entry != limit) {
> @@ -678,7 +705,11 @@
>  	}
>  }
>  
> +#ifdef CONFIG_SUNGEM_NAPI
> +static void gem_rx(struct gem *gp, int *work_done, int work_to_do)
> +#else
>  static void gem_rx(struct gem *gp)
> +#endif
>  {
>  	int entry, drops;
>  	u32 done;
> @@ -687,6 +718,8 @@
>  		printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
>  			gp->dev->name, readl(gp->regs + RXDMA_DONE), gp->rx_new);
>  
> +	gem_irq_acknowledge(gp, GREG_STAT_RXDONE);
> +
>  	entry = gp->rx_new;
>  	drops = 0;
>  	done = readl(gp->regs + RXDMA_DONE);
> @@ -713,6 +746,11 @@
>  				break;
>  		}
>  
> +#ifdef CONFIG_SUNGEM_NAPI
> +		if (*work_done >= work_to_do)
> +			break;
> +
> +#endif
>  		skb = gp->rx_skbs[entry];
>  
>  		len = (status & RXDCTRL_BUFSZ) >> 16;
> @@ -775,7 +813,12 @@
>  		skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff);
>  		skb->ip_summed = CHECKSUM_HW;
>  		skb->protocol = eth_type_trans(skb, gp->dev);
> +#ifdef CONFIG_SUNGEM_NAPI
> +		netif_receive_skb(skb);
> +		(*work_done)++;

minor nit:  surely it's better code to increment a local variable, then 
store the local to *work_done once all iterations are complete?


> +#else
>  		netif_rx(skb);
> +#endif
>  
>  		gp->net_stats.rx_packets++;
>  		gp->net_stats.rx_bytes += len;
> @@ -798,7 +841,7 @@
>  {
>  	struct net_device *dev = dev_id;
>  	struct gem *gp = dev->priv;
> -	u32 gem_status = readl(gp->regs + GREG_STAT);
> +	u32 gem_status = readl(gp->regs + GREG_STAT2);

what does this do?


>  	/* Swallow interrupts when shutting the chip down */
>  	if (gp->hw_running == 0)
> @@ -810,10 +853,21 @@
>  		if (gem_abnormal_irq(dev, gp, gem_status))
>  			goto out;
>  	}
> +
>  	if (gem_status & (GREG_STAT_TXALL | GREG_STAT_TXINTME))
>  		gem_tx(dev, gp, gem_status);
> -	if (gem_status & GREG_STAT_RXDONE)
> +
> +	if (gem_status & GREG_STAT_RXDONE) {
> +#ifdef CONFIG_SUNGEM_NAPI
> +		if (netif_rx_schedule_prep(dev)) {
> +			/* Disable interrupts and register for poll */
> +			gem_irq_disable(gp);
> +			__netif_rx_schedule(dev);
> +		}
> +#else
>  		gem_rx(gp);
> +#endif
> +	}
>  
>  out:
>  	spin_unlock(&gp->lock);
> @@ -821,6 +875,29 @@
>  	return IRQ_HANDLED;
>  }
>  
> +#ifdef CONFIG_SUNGEM_NAPI
> +static int gem_clean(struct net_device *dev, int *budget)
> +{
> +	struct gem *gp = dev->priv;
> +	int work_to_do = min(*budget, dev->quota);
> +	int work_done = 0;
> +	u32 gem_status = readl(gp->regs + GREG_STAT2);
> +
> +	if (gem_status & GREG_STAT_RXDONE)
> +		gem_rx(gp, &work_done, work_to_do);
> +
> +	*budget -= work_done;
> +	dev->quota -= work_done;
> +
> +	if (work_done < work_to_do || !netif_running(dev)) {
> +		__netif_rx_complete(dev);
> +		gem_irq_enable(gp, GREG_STAT_TXDONE);
> +	}
> +
> +	return (work_done >= work_to_do);
> +}
> +#endif
> +
>  static void gem_tx_timeout(struct net_device *dev)
>  {
>  	struct gem *gp = dev->priv;
> @@ -1018,7 +1096,7 @@
>  	u32 val;
>  
>  	/* Make sure we won't get any more interrupts */
> -	writel(0xffffffff, gp->regs + GREG_IMASK);
> +	gem_irq_disable(gp);
>  
>  	/* Reset the chip */
>  	writel(gp->swrst_base | GREG_SWRST_TXRST | GREG_SWRST_RXRST,
> @@ -1055,7 +1133,7 @@
>  	(void) readl(gp->regs + MAC_RXCFG);
>  	udelay(100);
>  
> -	writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
> +	gem_irq_enable(gp, GREG_STAT_TXDONE);
>  
>  	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
>  
> @@ -1323,7 +1401,7 @@
>  		/* Make sure we don't get interrupts or tx packets */
>  		netif_stop_queue(gp->dev);
>  
> -		writel(0xffffffff, gp->regs + GREG_IMASK);
> +		gem_irq_disable(gp);
>  
>  		/* Reset the chip & rings */
>  		gem_stop(gp);
> @@ -2220,7 +2298,7 @@
>  	spin_lock_irq(&gp->lock);
>  
>  	gp->opened = 0;	
> -	writel(0xffffffff, gp->regs + GREG_IMASK);
> +	gem_irq_disable(gp);
>  	netif_stop_queue(dev);
>  
>  	/* Stop chip */
> @@ -2264,7 +2342,7 @@
>  		/* Stop traffic, mark us closed */
>  		netif_device_detach(dev);
>  
> -		writel(0xffffffff, gp->regs + GREG_IMASK);
> +		gem_irq_disable(gp);
>  
>  		/* Stop chip */
>  		gem_stop(gp);

are all these enable/disables inside locks?

	Jeff

  reply	other threads:[~2004-09-14 15:56 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-09-14 15:35 [PATCH 2.6] Add NAPI support to sungem.c Harald Welte
2004-09-14 15:56 ` Jeff Garzik [this message]
2004-09-14 19:50   ` Harald Welte
2004-09-14 20:52     ` David S. Miller
2004-09-14 19:43 ` David S. Miller
2004-09-14 20:02   ` Harald Welte
2004-09-14 20:48     ` David S. Miller
2004-09-14 21:01       ` Jeff Garzik
2004-09-15 16:19         ` Manfred Spraul
2004-09-15  5:50     ` Eric Lemoine
2004-09-15 19:37       ` Harald Welte

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=41471498.8010107@pobox.com \
    --to=jgarzik@pobox.com \
    --cc=davem@davemloft.net \
    --cc=laforge@gnumonks.org \
    --cc=linuxppc-dev@lists.linuxppc.org \
    --cc=netdev@oss.sgi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).