Changeset 9664


Ignore:
Timestamp:
2007-12-07T01:03:06+01:00 (8 years ago)
Author:
nbd
Message:

[PATCH 1/2] Fix race between device reset and start_xmit

Signed-off-by: oliver@…

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/ar7/files/drivers/net/cpmac.c

    r9333 r9664  
    3838#include <linux/dma-mapping.h> 
    3939#include <asm/gpio.h> 
     40#include <asm/atomic.h> 
    4041 
    4142MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); 
     
    212213        struct work_struct reset_work; 
    213214        struct platform_device *pdev; 
     215        atomic_t reset_pending; 
    214216}; 
    215217 
     
    461463        struct cpmac_priv *priv = netdev_priv(dev); 
    462464 
     465        if (unlikely(atomic_read(&priv->reset_pending))) 
     466                return NETDEV_TX_BUSY; 
     467 
    463468        if (unlikely(skb_padto(skb, ETH_ZLEN))) 
    464469                return NETDEV_TX_OK; 
     
    640645                if (priv->desc_ring[i].skb) { 
    641646                        dev_kfree_skb_any(priv->desc_ring[i].skb); 
    642                         if (netif_subqueue_stopped(dev, i)) 
    643                             netif_wake_subqueue(dev, i); 
     647                        priv->desc_ring[i].skb = NULL; 
    644648                } 
    645649        } 
     
    648652static void cpmac_hw_error(struct work_struct *work) 
    649653{ 
     654        int i; 
    650655        struct cpmac_priv *priv = 
    651656                container_of(work, struct cpmac_priv, reset_work); 
     
    656661        cpmac_clear_tx(priv->dev); 
    657662        cpmac_hw_start(priv->dev); 
    658         netif_start_queue(priv->dev); 
     663        barrier(); 
     664        atomic_dec(&priv->reset_pending); 
     665         
     666        for (i = 0; i < CPMAC_QUEUES; i++) { 
     667                netif_wake_subqueue(priv->dev, i); 
     668        } 
     669        netif_wake_queue(priv->dev); 
     670} 
     671 
     672static void cpmac_check_status(struct net_device *dev) 
     673{ 
     674        struct cpmac_priv *priv = netdev_priv(dev); 
     675 
     676        u32 macstatus = cpmac_read(priv->regs, CPMAC_MAC_STATUS); 
     677        int rx_channel = (macstatus >> 8) & 7; 
     678        int rx_code = (macstatus >> 12) & 15; 
     679        int tx_channel = (macstatus >> 16) & 7; 
     680        int tx_code = (macstatus >> 20) & 15; 
     681 
     682        if (rx_code || tx_code) { 
     683                if (netif_msg_drv(priv) && net_ratelimit()) { 
     684                        /* Can't find any documentation on what these error codes actually are. 
     685                         * So just log them and hope.. 
     686                         */ 
     687                        if (rx_code) 
     688                                printk(KERN_WARNING "%s: host error %d on rx channel %d (macstatus %08x), resetting\n", 
     689                                       dev->name, rx_code, rx_channel, macstatus); 
     690                        if (tx_code) 
     691                                printk(KERN_WARNING "%s: host error %d on tx channel %d (macstatus %08x), resetting\n", 
     692                                       dev->name, tx_code, tx_channel, macstatus); 
     693                } 
     694                 
     695                netif_stop_queue(dev); 
     696                cpmac_hw_stop(dev); 
     697                if (schedule_work(&priv->reset_work)) 
     698                        atomic_inc(&priv->reset_pending);                        
     699                if (unlikely(netif_msg_hw(priv))) 
     700                        cpmac_dump_regs(dev); 
     701        } 
    659702} 
    660703 
     
    688731        cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0); 
    689732 
    690         if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) { 
    691                 if (netif_msg_drv(priv) && net_ratelimit()) 
    692                         printk(KERN_ERR "%s: hw error, resetting...\n", 
    693                                dev->name); 
    694                 netif_stop_queue(dev); 
    695                 cpmac_hw_stop(dev); 
    696                 schedule_work(&priv->reset_work); 
    697                 if (unlikely(netif_msg_hw(priv))) 
    698                         cpmac_dump_regs(dev); 
    699         } 
     733        if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) 
     734                cpmac_check_status(dev); 
    700735 
    701736        return IRQ_HANDLED; 
     
    704739static void cpmac_tx_timeout(struct net_device *dev) 
    705740{ 
    706         struct cpmac_priv *priv = netdev_priv(dev); 
    707741        int i; 
     742        struct cpmac_priv *priv = netdev_priv(dev); 
    708743 
    709744        spin_lock(&priv->lock); 
     
    712747        if (netif_msg_tx_err(priv) && net_ratelimit()) 
    713748                printk(KERN_WARNING "%s: transmit timeout\n", dev->name); 
    714         /*  
    715          * FIXME: waking up random queue is not the best thing to 
    716          * do... on the other hand why we got here at all? 
    717          */ 
    718 #ifdef CONFIG_NETDEVICES_MULTIQUEUE 
    719         for (i = 0; i < CPMAC_QUEUES; i++) 
    720                 if (priv->desc_ring[i].skb) { 
    721                         priv->desc_ring[i].dataflags = 0; 
    722                         dev_kfree_skb_any(priv->desc_ring[i].skb); 
    723                         netif_wake_subqueue(dev, i); 
    724                         break; 
    725                 } 
    726 #else 
    727         priv->desc_ring[0].dataflags = 0; 
    728         if (priv->desc_ring[0].skb) 
    729                 dev_kfree_skb_any(priv->desc_ring[0].skb); 
    730         netif_wake_queue(dev); 
    731 #endif 
     749 
     750        atomic_inc(&priv->reset_pending); 
     751        barrier(); 
     752        cpmac_clear_tx(dev); 
     753        barrier(); 
     754        atomic_dec(&priv->reset_pending); 
     755 
     756        netif_wake_queue(priv->dev); 
     757        for (i = 0; i < CPMAC_QUEUES; i++) { 
     758                netif_wake_subqueue(dev, i); 
     759        } 
    732760} 
    733761 
     
    925953        } 
    926954 
     955        atomic_set(&priv->reset_pending, 0); 
    927956        INIT_WORK(&priv->reset_work, cpmac_hw_error); 
    928957        cpmac_hw_start(dev); 
Note: See TracChangeset for help on using the changeset viewer.