aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2007-08-20 19:33:42 -0400
committerJeff Garzik <jeff@garzik.org>2007-08-25 02:31:04 -0400
commitc46ac9463fbdee41723dd9fd108b2c1ffd30615f (patch)
treee1f4acf314fa85c259284dc729640b1fcb71dbea /drivers/net
parentbc1e0a095e9b8c4df4a2eedd7dc6a9d470a0e6b7 (diff)
DM9000: fix interface hang under load
When transferring data at full speed, the DM9000 network interface sometimes stops sending/receiving data. Worse, ksoftirqd consumes 100% cpu and the net tx watchdog never triggers. Fix by spin_lock_irqsave() in dm9000_start_xmit() to prevent the interrupt handler from interfering. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/dm9000.c25
1 files changed, 7 insertions, 18 deletions
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index c3de81bf090a..738aa5906514 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -700,6 +700,7 @@ dm9000_init_dm9000(struct net_device *dev)
700static int 700static int
701dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) 701dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
702{ 702{
703 unsigned long flags;
703 board_info_t *db = (board_info_t *) dev->priv; 704 board_info_t *db = (board_info_t *) dev->priv;
704 705
705 PRINTK3("dm9000_start_xmit\n"); 706 PRINTK3("dm9000_start_xmit\n");
@@ -707,10 +708,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
707 if (db->tx_pkt_cnt > 1) 708 if (db->tx_pkt_cnt > 1)
708 return 1; 709 return 1;
709 710
710 netif_stop_queue(dev); 711 spin_lock_irqsave(&db->lock, flags);
711
712 /* Disable all interrupts */
713 iow(db, DM9000_IMR, IMR_PAR);
714 712
715 /* Move data to DM9000 TX RAM */ 713 /* Move data to DM9000 TX RAM */
716 writeb(DM9000_MWCMD, db->io_addr); 714 writeb(DM9000_MWCMD, db->io_addr);
@@ -718,12 +716,9 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
718 (db->outblk)(db->io_data, skb->data, skb->len); 716 (db->outblk)(db->io_data, skb->data, skb->len);
719 db->stats.tx_bytes += skb->len; 717 db->stats.tx_bytes += skb->len;
720 718
719 db->tx_pkt_cnt++;
721 /* TX control: First packet immediately send, second packet queue */ 720 /* TX control: First packet immediately send, second packet queue */
722 if (db->tx_pkt_cnt == 0) { 721 if (db->tx_pkt_cnt == 1) {
723
724 /* First Packet */
725 db->tx_pkt_cnt++;
726
727 /* Set TX length to DM9000 */ 722 /* Set TX length to DM9000 */
728 iow(db, DM9000_TXPLL, skb->len & 0xff); 723 iow(db, DM9000_TXPLL, skb->len & 0xff);
729 iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff); 724 iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);
@@ -732,23 +727,17 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
732 iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ 727 iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
733 728
734 dev->trans_start = jiffies; /* save the time stamp */ 729 dev->trans_start = jiffies; /* save the time stamp */
735
736 } else { 730 } else {
737 /* Second packet */ 731 /* Second packet */
738 db->tx_pkt_cnt++;
739 db->queue_pkt_len = skb->len; 732 db->queue_pkt_len = skb->len;
733 netif_stop_queue(dev);
740 } 734 }
741 735
736 spin_unlock_irqrestore(&db->lock, flags);
737
742 /* free this SKB */ 738 /* free this SKB */
743 dev_kfree_skb(skb); 739 dev_kfree_skb(skb);
744 740
745 /* Re-enable resource check */
746 if (db->tx_pkt_cnt == 1)
747 netif_wake_queue(dev);
748
749 /* Re-enable interrupt */
750 iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
751
752 return 0; 741 return 0;
753} 742}
754 743