diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2014-06-05 13:22:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-05 18:36:54 -0400 |
commit | d8498088cf466483093c9a29121e3833e7923287 (patch) | |
tree | 04e2c004671adb5d276b7c6d6f7d706b0f889c75 /drivers/net/ethernet/broadcom | |
parent | 6934e79ed1221a38f20704bf52ed588a16985fc0 (diff) |
net: systemport: fix transmit locking scheme
Our transmit locking scheme did not account for the TX ring full
interrupt. If a TX ring full interrupt fires while we are attempting to
transmit, we will cause a deadlock to occur. Fix this by making sure
that we properly disable interrupts while acquiring the spinlock.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom')
-rw-r--r-- | drivers/net/ethernet/broadcom/bcmsysport.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 25982b02f0ea..4dfc93fe9744 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c | |||
@@ -637,10 +637,11 @@ static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, | |||
637 | struct bcm_sysport_tx_ring *ring) | 637 | struct bcm_sysport_tx_ring *ring) |
638 | { | 638 | { |
639 | unsigned int released; | 639 | unsigned int released; |
640 | unsigned long flags; | ||
640 | 641 | ||
641 | spin_lock(&ring->lock); | 642 | spin_lock_irqsave(&ring->lock, flags); |
642 | released = __bcm_sysport_tx_reclaim(priv, ring); | 643 | released = __bcm_sysport_tx_reclaim(priv, ring); |
643 | spin_unlock(&ring->lock); | 644 | spin_unlock_irqrestore(&ring->lock, flags); |
644 | 645 | ||
645 | return released; | 646 | return released; |
646 | } | 647 | } |
@@ -822,6 +823,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, | |||
822 | struct netdev_queue *txq; | 823 | struct netdev_queue *txq; |
823 | struct dma_desc *desc; | 824 | struct dma_desc *desc; |
824 | unsigned int skb_len; | 825 | unsigned int skb_len; |
826 | unsigned long flags; | ||
825 | dma_addr_t mapping; | 827 | dma_addr_t mapping; |
826 | u32 len_status; | 828 | u32 len_status; |
827 | u16 queue; | 829 | u16 queue; |
@@ -831,8 +833,8 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, | |||
831 | txq = netdev_get_tx_queue(dev, queue); | 833 | txq = netdev_get_tx_queue(dev, queue); |
832 | ring = &priv->tx_rings[queue]; | 834 | ring = &priv->tx_rings[queue]; |
833 | 835 | ||
834 | /* lock against tx reclaim in BH context */ | 836 | /* lock against tx reclaim in BH context and TX ring full interrupt */ |
835 | spin_lock(&ring->lock); | 837 | spin_lock_irqsave(&ring->lock, flags); |
836 | if (unlikely(ring->desc_count == 0)) { | 838 | if (unlikely(ring->desc_count == 0)) { |
837 | netif_tx_stop_queue(txq); | 839 | netif_tx_stop_queue(txq); |
838 | netdev_err(dev, "queue %d awake and ring full!\n", queue); | 840 | netdev_err(dev, "queue %d awake and ring full!\n", queue); |
@@ -914,7 +916,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, | |||
914 | 916 | ||
915 | ret = NETDEV_TX_OK; | 917 | ret = NETDEV_TX_OK; |
916 | out: | 918 | out: |
917 | spin_unlock(&ring->lock); | 919 | spin_unlock_irqrestore(&ring->lock, flags); |
918 | return ret; | 920 | return ret; |
919 | } | 921 | } |
920 | 922 | ||