From 3f735b76a4e654bee652cbbeb405b9b3ef950316 Mon Sep 17 00:00:00 2001 From: Francois Romieu <romieu@fr.zoreil.com> Date: Wed, 8 Mar 2006 22:41:15 +0100 Subject: [PATCH 1/5] de2104x: prevent interrupt before the interrupt handler is registered de_init_hw enables the irq thus it must be issued after request_irq. Signed-off-by: Martin Michlmayr <tbm@cyrius.com> Signed-off-by: Francois Romieu <romieu@fr.zoreil.com> --- drivers/net/tulip/de2104x.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d7fb3ffe06ac..9e9e1fe92914 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1362,7 +1362,6 @@ static int de_open (struct net_device *dev) { struct de_private *de = dev->priv; int rc; - unsigned long flags; if (netif_msg_ifup(de)) printk(KERN_DEBUG "%s: enabling interface\n", dev->name); @@ -1376,18 +1375,20 @@ static int de_open (struct net_device *dev) return rc; } - rc = de_init_hw(de); - if (rc) { - printk(KERN_ERR "%s: h/w init failure, err=%d\n", - dev->name, rc); - goto err_out_free; - } + dw32(IntrMask, 0); rc = request_irq(dev->irq, de_interrupt, SA_SHIRQ, dev->name, dev); if (rc) { printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n", dev->name, dev->irq, rc); - goto err_out_hw; + goto err_out_free; + } + + rc = de_init_hw(de); + if (rc) { + printk(KERN_ERR "%s: h/w init failure, err=%d\n", + dev->name, rc); + goto err_out_free_irq; } netif_start_queue(dev); @@ -1395,11 +1396,8 @@ static int de_open (struct net_device *dev) return 0; -err_out_hw: - spin_lock_irqsave(&de->lock, flags); - de_stop_hw(de); - spin_unlock_irqrestore(&de->lock, flags); - +err_out_free_irq: + free_irq(dev->irq, dev); err_out_free: de_free_rings(de); return rc; From 39bf4295bb4bcb0c108f74b72dd2eb5b9b9dfacc Mon Sep 17 00:00:00 2001 From: Francois Romieu <romieu@fr.zoreil.com> Date: Wed, 8 Mar 2006 22:45:52 +0100 Subject: [PATCH 2/5] de2104x: fix the TX watchdog Insert de_init_rings() to reinit the rings before de_init_hw() tries to access them again. Signed-off-by: Francois Romieu <romieu@fr.zoreil.com> --- drivers/net/tulip/de2104x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 9e9e1fe92914..2d0cfbceee22 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1453,6 +1453,8 @@ static void de_tx_timeout (struct net_device *dev) synchronize_irq(dev->irq); de_clean_rings(de); + de_init_rings(de); + de_init_hw(de); netif_wake_queue(dev); From 28a31860191c0d5710d42f85510daac0a3c26a01 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@osdl.org> Date: Tue, 7 Mar 2006 11:06:35 -0800 Subject: [PATCH 3/5] sky2: not random enough Don't use sky2 to seed random pool beacause the network packet arrival time will not be truly random due to NAPI and interrupt mitigation. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- drivers/net/sky2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 72c1630977d6..dc4feaf79be2 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3243,8 +3243,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, } } - err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, - DRV_NAME, hw); + err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw); if (err) { printk(KERN_ERR PFX "%s: cannot assign irq %d\n", pci_name(pdev), pdev->irq); From b19666d92009ad2aa8e12d25f2cab59fb32421eb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@osdl.org> Date: Tue, 7 Mar 2006 11:06:36 -0800 Subject: [PATCH 4/5] sky2: force early transmit interrupts Avoid premature transmit ring full conditions. Force a transmit status interrupt if transmit ring gets nearly full and after a TSO send. Allow more entries in transmit ring to be used if dma_addr is 32 bits Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- drivers/net/sky2.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index dc4feaf79be2..1078b7cab076 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -74,7 +74,7 @@ #define TX_RING_SIZE 512 #define TX_DEF_PENDING (TX_RING_SIZE - 1) #define TX_MIN_PENDING 64 -#define MAX_SKB_TX_LE (4 + 2*MAX_SKB_FRAGS) +#define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS) #define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */ #define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le)) @@ -1145,6 +1145,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) struct sky2_tx_le *le = NULL; struct tx_ring_info *re; unsigned i, len; + int avail; dma_addr_t mapping; u32 addr64; u16 mss; @@ -1287,12 +1288,16 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) re->idx = sky2->tx_prod; le->ctrl |= EOP; + avail = tx_avail(sky2); + if (mss != 0 || avail < TX_MIN_PENDING) { + le->ctrl |= FRC_STAT; + if (avail <= MAX_SKB_TX_LE) + netif_stop_queue(dev); + } + sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod, &sky2->tx_last_put, TX_RING_SIZE); - if (tx_avail(sky2) <= MAX_SKB_TX_LE) - netif_stop_queue(dev); - out_unlock: spin_unlock(&sky2->tx_lock); From 70f1be4812a833ac856818c3149e432ff6a84c2e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@osdl.org> Date: Tue, 7 Mar 2006 11:06:37 -0800 Subject: [PATCH 5/5] sky2: truncate oversize packets Turn on truncation to prevent getting choked by frames larger than expected. Without this fix, driver hangs after receiving an oversize packet. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- drivers/net/sky2.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1078b7cab076..73260364cba3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -622,8 +622,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) /* Configure Rx MAC FIFO */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); - sky2_write16(hw, SK_REG(port, RX_GMF_CTRL_T), - GMF_RX_CTRL_DEF); + sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), + GMF_OPER_ON | GMF_RX_F_FL_ON); /* Flush Rx MAC FIFO on any flow control or error */ sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR); @@ -995,6 +995,10 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2_rx_add(sky2, re->mapaddr); } + /* Truncate oversize frames */ + sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), sky2->rx_bufsize - 8); + sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON); + /* Tell chip about available buffers */ sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put); sky2->rx_last_put = sky2_read16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX)); @@ -1712,10 +1716,12 @@ static void sky2_tx_timeout(struct net_device *dev) #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -/* Want receive buffer size to be multiple of 64 bits, and incl room for vlan */ +/* Want receive buffer size to be multiple of 64 bits + * and incl room for vlan and truncation + */ static inline unsigned sky2_buf_size(int mtu) { - return roundup(mtu + ETH_HLEN + 4, 8); + return roundup(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8; } static int sky2_change_mtu(struct net_device *dev, int new_mtu) @@ -1798,7 +1804,7 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2, if (!(status & GMR_FS_RX_OK)) goto resubmit; - if ((status >> 16) != length || length > sky2->rx_bufsize) + if (length > sky2->netdev->mtu + ETH_HLEN) goto oversize; if (length < copybreak) {