From 2d38caba5fd148976f54930782e8209fa45879a0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Oct 2006 19:52:31 +0100 Subject: [PATCH] ep93xx_eth: fix RX/TXstatus ring full handling Ray Lehtiniemi reported that an incoming UDP packet flood can lock up the ep93xx ethernet driver. Herbert Valerio Riedel noted that due to the way ep93xx_eth manages the RX/TXstatus rings, it cannot distinguish a full ring from an empty one, and correctly suggested that this was likely to be causing this lockup to occur. Instead of looking at the hardware's RX/TXstatus ring write pointers to determine when to stop reading from those rings, we should just check every individual RX/TXstatus descriptor's valid bit instead, since there is no other way to distinguish an empty ring from a full ring, and if there is a descriptor waiting, we take the hit of reading the descriptor from memory anyway. Signed-off-by: Lennert Buytenhek Signed-off-by: Jeff Garzik --- drivers/net/arm/ep93xx_eth.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'drivers/net/arm') diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 127561c782fd..2fc8b2a1a023 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -193,12 +193,9 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev) static int ep93xx_rx(struct net_device *dev, int *budget) { struct ep93xx_priv *ep = netdev_priv(dev); - int tail_offset; int rx_done; int processed; - tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr; - rx_done = 0; processed = 0; while (*budget > 0) { @@ -211,28 +208,23 @@ static int ep93xx_rx(struct net_device *dev, int *budget) entry = ep->rx_pointer; rstat = ep->descs->rstat + entry; - if ((void *)rstat - (void *)ep->descs == tail_offset) { + + rstat0 = rstat->rstat0; + rstat1 = rstat->rstat1; + if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) { rx_done = 1; break; } - rstat0 = rstat->rstat0; - rstat1 = rstat->rstat1; rstat->rstat0 = 0; rstat->rstat1 = 0; - if (!(rstat0 & RSTAT0_RFP)) - printk(KERN_CRIT "ep93xx_rx: buffer not done " - " %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_EOF)) printk(KERN_CRIT "ep93xx_rx: not end-of-frame " " %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_EOB)) printk(KERN_CRIT "ep93xx_rx: not end-of-buffer " " %.8x %.8x\n", rstat0, rstat1); - if (!(rstat1 & RSTAT1_RFP)) - printk(KERN_CRIT "ep93xx_rx: buffer1 not done " - " %.8x %.8x\n", rstat0, rstat1); if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) printk(KERN_CRIT "ep93xx_rx: entry mismatch " " %.8x %.8x\n", rstat0, rstat1); @@ -301,13 +293,8 @@ err: static int ep93xx_have_more_rx(struct ep93xx_priv *ep) { - struct ep93xx_rstat *rstat; - int tail_offset; - - rstat = ep->descs->rstat + ep->rx_pointer; - tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr; - - return !((void *)rstat - (void *)ep->descs == tail_offset); + struct ep93xx_rstat *rstat = ep->descs->rstat + ep->rx_pointer; + return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP)); } static int ep93xx_poll(struct net_device *dev, int *budget) @@ -379,10 +366,8 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) static void ep93xx_tx_complete(struct net_device *dev) { struct ep93xx_priv *ep = netdev_priv(dev); - int tail_offset; int wake; - tail_offset = rdl(ep, REG_TXSTSQCURADD) - ep->descs_dma_addr; wake = 0; spin_lock(&ep->tx_pending_lock); @@ -393,15 +378,13 @@ static void ep93xx_tx_complete(struct net_device *dev) entry = ep->tx_clean_pointer; tstat = ep->descs->tstat + entry; - if ((void *)tstat - (void *)ep->descs == tail_offset) - break; tstat0 = tstat->tstat0; + if (!(tstat0 & TSTAT0_TXFP)) + break; + tstat->tstat0 = 0; - if (!(tstat0 & TSTAT0_TXFP)) - printk(KERN_CRIT "ep93xx_tx_complete: buffer not done " - " %.8x\n", tstat0); if (tstat0 & TSTAT0_FA) printk(KERN_CRIT "ep93xx_tx_complete: frame aborted " " %.8x\n", tstat0); -- cgit v1.2.3 From 79c356f44b26da9fe357ed1a11e7faec4fd94e13 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Oct 2006 19:52:54 +0100 Subject: [PATCH] ep93xx_eth: fix unlikely(x) > y test Fix unlikely(x) > y test in ep93xx_eth. Signed-off-by: Lennert Buytenhek Signed-off-by: Jeff Garzik --- drivers/net/arm/ep93xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/arm') diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 2fc8b2a1a023..90d77ec48fb6 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -334,7 +334,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) struct ep93xx_priv *ep = netdev_priv(dev); int entry; - if (unlikely(skb->len) > MAX_PKT_SIZE) { + if (unlikely(skb->len > MAX_PKT_SIZE)) { ep->stats.tx_dropped++; dev_kfree_skb(skb); return NETDEV_TX_OK; -- cgit v1.2.3 From 06f0015ace46ce9d313ec02d6b13c47c8e795a6c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Oct 2006 19:54:08 +0100 Subject: [PATCH] ep93xx_eth: don't report RX errors Flooding the console with error messages for every RX FIFO overrun, checksum error and framing error isn't very sensible. Each of these errors can occur during normal operation, so stop printk'ing error messages for RX errors at all. Signed-off-by: Lennert Buytenhek Signed-off-by: Jeff Garzik --- drivers/net/arm/ep93xx_eth.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/arm') diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 90d77ec48fb6..8ebd68e2af98 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -230,9 +230,6 @@ static int ep93xx_rx(struct net_device *dev, int *budget) " %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_RWE)) { - printk(KERN_NOTICE "ep93xx_rx: receive error " - " %.8x %.8x\n", rstat0, rstat1); - ep->stats.rx_errors++; if (rstat0 & RSTAT0_OE) ep->stats.rx_fifo_errors++; -- cgit v1.2.3 From 6c3561b0c1b64c8f0d1419f3909ab29f0eb98906 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 00:19:36 +0100 Subject: [PATCH] beginning of 8390 fixes - generic and arm/etherh etherh and a handful of other odd drivers use different macros when building 8390.c. Since we generate a single 8390.o and then link with it, in any config with both oddball and normal 8390-based driver we will end up with breakage in at least one of them. Solution: take most of 8390.c into lib8390.c and have 8390.c, etherh.c and the rest of oddballs #include it. Helper macros are taken from 8390.h to whoever includes lib8390.c. That way odd drivers get separate instances of compiled 8390 stuff and stop stepping on each other's toes. 8390.h gets cleaned up - we don't have the cascade of ifdefs in there and are left with the stuff that can be used by any 8390-based driver. Current problems are exactly because of that cascade - we attempt to choose the set of helpers by looking at config and that, of course, doesn't work well when we have several sets needed by various drivers in our config. Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/arm/etherh.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers/net/arm') diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 4ae98970b282..747a71f5dd0e 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -52,7 +52,12 @@ #include #include -#include "../8390.h" +#define EI_SHIFT(x) (ei_local->reg_offset[x]) + +#define ei_inb(_p) readb(_p) +#define ei_outb(_v,_p) writeb(_v,_p) +#define ei_inb_p(_p) readb(_p) +#define ei_outb_p(_v,_p) writeb(_v,_p) #define NET_DEBUG 0 #define DEBUG_INIT 2 @@ -60,6 +65,11 @@ #define DRV_NAME "etherh" #define DRV_VERSION "1.11" +static char version[] __initdata = + "EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n"; + +#include "../lib8390.c" + static unsigned int net_debug = NET_DEBUG; struct etherh_priv { @@ -87,9 +97,6 @@ MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("EtherH/EtherM driver"); MODULE_LICENSE("GPL"); -static char version[] __initdata = - "EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n"; - #define ETHERH500_DATAPORT 0x800 /* MEMC */ #define ETHERH500_NS8390 0x000 /* MEMC */ #define ETHERH500_CTRLPORT 0x800 /* IOC */ @@ -360,7 +367,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf printk(KERN_ERR "%s: timeout waiting for TX RDC\n", dev->name); etherh_reset (dev); - NS8390_init (dev, 1); + __NS8390_init (dev, 1); break; } @@ -465,7 +472,7 @@ etherh_open(struct net_device *dev) return -EINVAL; } - if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)) + if (request_irq(dev->irq, __ei_interrupt, 0, dev->name, dev)) return -EAGAIN; /* @@ -491,7 +498,7 @@ etherh_open(struct net_device *dev) etherh_setif(dev); etherh_reset(dev); - ei_open(dev); + __ei_open(dev); return 0; } @@ -502,7 +509,7 @@ etherh_open(struct net_device *dev) static int etherh_close(struct net_device *dev) { - ei_close (dev); + __ei_close (dev); free_irq (dev->irq, dev); return 0; } @@ -650,7 +657,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto out; - dev = __alloc_ei_netdev(sizeof(struct etherh_priv)); + dev = ____alloc_ei_netdev(sizeof(struct etherh_priv)); if (!dev) { ret = -ENOMEM; goto release; @@ -736,7 +743,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) ei_local->interface_num = 0; etherh_reset(dev); - NS8390_init(dev, 0); + __NS8390_init(dev, 0); ret = register_netdev(dev); if (ret) -- cgit v1.2.3 From b936889c8f95b601d3ef6caac6ac653a8adb4fec Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 00:19:36 +0100 Subject: [PATCH] 8390 cleanup - etherh iomem annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/arm/etherh.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net/arm') diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 747a71f5dd0e..f3faa4fe58e7 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -54,10 +54,10 @@ #define EI_SHIFT(x) (ei_local->reg_offset[x]) -#define ei_inb(_p) readb(_p) -#define ei_outb(_v,_p) writeb(_v,_p) -#define ei_inb_p(_p) readb(_p) -#define ei_outb_p(_v,_p) writeb(_v,_p) +#define ei_inb(_p) readb((void __iomem *)_p) +#define ei_outb(_v,_p) writeb(_v,(void __iomem *)_p) +#define ei_inb_p(_p) readb((void __iomem *)_p) +#define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p) #define NET_DEBUG 0 #define DEBUG_INIT 2 @@ -184,7 +184,7 @@ etherh_setif(struct net_device *dev) switch (etherh_priv(dev)->id) { case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - addr = (void *)dev->base_addr + EN0_RCNTHI; + addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; switch (dev->if_port) { case IF_PORT_10BASE2: @@ -225,7 +225,7 @@ etherh_getifstat(struct net_device *dev) switch (etherh_priv(dev)->id) { case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - addr = (void *)dev->base_addr + EN0_RCNTHI; + addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; switch (dev->if_port) { case IF_PORT_10BASE2: stat = 1; @@ -288,7 +288,7 @@ static void etherh_reset(struct net_device *dev) { struct ei_device *ei_local = netdev_priv(dev); - void __iomem *addr = (void *)dev->base_addr; + void __iomem *addr = (void __iomem *)dev->base_addr; writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr); @@ -334,7 +334,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf ei_local->dmaing = 1; - addr = (void *)dev->base_addr; + addr = (void __iomem *)dev->base_addr; dma_base = etherh_priv(dev)->dma_base; count = (count + 1) & ~1; @@ -394,7 +394,7 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ei_local->dmaing = 1; - addr = (void *)dev->base_addr; + addr = (void __iomem *)dev->base_addr; dma_base = etherh_priv(dev)->dma_base; buf = skb->data; @@ -434,7 +434,7 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p ei_local->dmaing = 1; - addr = (void *)dev->base_addr; + addr = (void __iomem *)dev->base_addr; dma_base = etherh_priv(dev)->dma_base; writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); -- cgit v1.2.3