diff options
author | Alexander Duyck <alexander.h.duyck@intel.com> | 2009-03-18 21:12:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-20 04:17:20 -0400 |
commit | 1b7719c4559dc1522065d4cfd033f8bb8f969159 (patch) | |
tree | d38b95cbe779ac1d9db46f3460d760653bce8dc0 /drivers/net | |
parent | 8c81c9c315b7e7e240906fab0e8dde1595101bd2 (diff) |
e1000e: fix dma error handling issues
There were a few issues I noticed in e1000e. These include a double free
of the skb if mapping fails, and the fact that context descriptors appear
to be left in the descriptor ring after the failure.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/e1000e/netdev.c | 76 |
1 files changed, 32 insertions, 44 deletions
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 402d2dd7d68f..da876d59a9ca 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -574,6 +574,7 @@ static void e1000_put_txbuf(struct e1000_adapter *adapter, | |||
574 | dev_kfree_skb_any(buffer_info->skb); | 574 | dev_kfree_skb_any(buffer_info->skb); |
575 | buffer_info->skb = NULL; | 575 | buffer_info->skb = NULL; |
576 | } | 576 | } |
577 | buffer_info->time_stamp = 0; | ||
577 | } | 578 | } |
578 | 579 | ||
579 | static void e1000_print_tx_hang(struct e1000_adapter *adapter) | 580 | static void e1000_print_tx_hang(struct e1000_adapter *adapter) |
@@ -678,17 +679,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) | |||
678 | } | 679 | } |
679 | 680 | ||
680 | if (adapter->detect_tx_hung) { | 681 | if (adapter->detect_tx_hung) { |
681 | /* | 682 | /* Detect a transmit hang in hardware, this serializes the |
682 | * Detect a transmit hang in hardware, this serializes the | 683 | * check with the clearing of time_stamp and movement of i */ |
683 | * check with the clearing of time_stamp and movement of i | ||
684 | */ | ||
685 | adapter->detect_tx_hung = 0; | 684 | adapter->detect_tx_hung = 0; |
686 | /* | 685 | if (tx_ring->buffer_info[eop].time_stamp && |
687 | * read barrier to make sure that the ->dma member and time | ||
688 | * stamp are updated fully | ||
689 | */ | ||
690 | smp_rmb(); | ||
691 | if (tx_ring->buffer_info[eop].dma && | ||
692 | time_after(jiffies, tx_ring->buffer_info[eop].time_stamp | 686 | time_after(jiffies, tx_ring->buffer_info[eop].time_stamp |
693 | + (adapter->tx_timeout_factor * HZ)) | 687 | + (adapter->tx_timeout_factor * HZ)) |
694 | && !(er32(STATUS) & E1000_STATUS_TXOFF)) { | 688 | && !(er32(STATUS) & E1000_STATUS_TXOFF)) { |
@@ -3824,39 +3818,41 @@ static int e1000_tx_map(struct e1000_adapter *adapter, | |||
3824 | unsigned int mss) | 3818 | unsigned int mss) |
3825 | { | 3819 | { |
3826 | struct e1000_ring *tx_ring = adapter->tx_ring; | 3820 | struct e1000_ring *tx_ring = adapter->tx_ring; |
3821 | struct e1000_buffer *buffer_info; | ||
3827 | unsigned int len = skb_headlen(skb); | 3822 | unsigned int len = skb_headlen(skb); |
3828 | unsigned int offset, size, count = 0, i; | 3823 | unsigned int offset, size, count = 0, i; |
3829 | unsigned int f; | 3824 | unsigned int f; |
3830 | dma_addr_t map; | 3825 | dma_addr_t *map; |
3831 | 3826 | ||
3832 | i = tx_ring->next_to_use; | 3827 | i = tx_ring->next_to_use; |
3833 | 3828 | ||
3834 | if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { | 3829 | if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { |
3835 | dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); | 3830 | dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); |
3836 | adapter->tx_dma_failed++; | 3831 | adapter->tx_dma_failed++; |
3837 | dev_kfree_skb(skb); | 3832 | return 0; |
3838 | return -2; | ||
3839 | } | 3833 | } |
3840 | 3834 | ||
3841 | map = skb_shinfo(skb)->dma_maps[0]; | 3835 | map = skb_shinfo(skb)->dma_maps; |
3842 | offset = 0; | 3836 | offset = 0; |
3843 | 3837 | ||
3844 | while (len) { | 3838 | while (len) { |
3845 | struct e1000_buffer *buffer_info = &tx_ring->buffer_info[i]; | 3839 | buffer_info = &tx_ring->buffer_info[i]; |
3846 | size = min(len, max_per_txd); | 3840 | size = min(len, max_per_txd); |
3847 | 3841 | ||
3848 | buffer_info->length = size; | 3842 | buffer_info->length = size; |
3849 | /* set time_stamp *before* dma to help avoid a possible race */ | ||
3850 | buffer_info->time_stamp = jiffies; | 3843 | buffer_info->time_stamp = jiffies; |
3851 | buffer_info->dma = map + offset; | ||
3852 | buffer_info->next_to_watch = i; | 3844 | buffer_info->next_to_watch = i; |
3845 | buffer_info->dma = map[0] + offset; | ||
3846 | count++; | ||
3853 | 3847 | ||
3854 | len -= size; | 3848 | len -= size; |
3855 | offset += size; | 3849 | offset += size; |
3856 | count++; | 3850 | |
3857 | i++; | 3851 | if (len) { |
3858 | if (i == tx_ring->count) | 3852 | i++; |
3859 | i = 0; | 3853 | if (i == tx_ring->count) |
3854 | i = 0; | ||
3855 | } | ||
3860 | } | 3856 | } |
3861 | 3857 | ||
3862 | for (f = 0; f < nr_frags; f++) { | 3858 | for (f = 0; f < nr_frags; f++) { |
@@ -3864,37 +3860,29 @@ static int e1000_tx_map(struct e1000_adapter *adapter, | |||
3864 | 3860 | ||
3865 | frag = &skb_shinfo(skb)->frags[f]; | 3861 | frag = &skb_shinfo(skb)->frags[f]; |
3866 | len = frag->size; | 3862 | len = frag->size; |
3867 | map = skb_shinfo(skb)->dma_maps[f + 1]; | ||
3868 | offset = 0; | 3863 | offset = 0; |
3869 | 3864 | ||
3870 | while (len) { | 3865 | while (len) { |
3871 | struct e1000_buffer *buffer_info; | 3866 | i++; |
3867 | if (i == tx_ring->count) | ||
3868 | i = 0; | ||
3869 | |||
3872 | buffer_info = &tx_ring->buffer_info[i]; | 3870 | buffer_info = &tx_ring->buffer_info[i]; |
3873 | size = min(len, max_per_txd); | 3871 | size = min(len, max_per_txd); |
3874 | 3872 | ||
3875 | buffer_info->length = size; | 3873 | buffer_info->length = size; |
3876 | buffer_info->time_stamp = jiffies; | 3874 | buffer_info->time_stamp = jiffies; |
3877 | buffer_info->dma = map + offset; | ||
3878 | buffer_info->next_to_watch = i; | 3875 | buffer_info->next_to_watch = i; |
3876 | buffer_info->dma = map[f + 1] + offset; | ||
3879 | 3877 | ||
3880 | len -= size; | 3878 | len -= size; |
3881 | offset += size; | 3879 | offset += size; |
3882 | count++; | 3880 | count++; |
3883 | |||
3884 | i++; | ||
3885 | if (i == tx_ring->count) | ||
3886 | i = 0; | ||
3887 | } | 3881 | } |
3888 | } | 3882 | } |
3889 | 3883 | ||
3890 | if (i == 0) | ||
3891 | i = tx_ring->count - 1; | ||
3892 | else | ||
3893 | i--; | ||
3894 | |||
3895 | tx_ring->buffer_info[i].skb = skb; | 3884 | tx_ring->buffer_info[i].skb = skb; |
3896 | tx_ring->buffer_info[first].next_to_watch = i; | 3885 | tx_ring->buffer_info[first].next_to_watch = i; |
3897 | smp_wmb(); | ||
3898 | 3886 | ||
3899 | return count; | 3887 | return count; |
3900 | } | 3888 | } |
@@ -4145,20 +4133,20 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
4145 | if (skb->protocol == htons(ETH_P_IP)) | 4133 | if (skb->protocol == htons(ETH_P_IP)) |
4146 | tx_flags |= E1000_TX_FLAGS_IPV4; | 4134 | tx_flags |= E1000_TX_FLAGS_IPV4; |
4147 | 4135 | ||
4136 | /* if count is 0 then mapping error has occured */ | ||
4148 | count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); | 4137 | count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); |
4149 | if (count < 0) { | 4138 | if (count) { |
4150 | /* handle pci_map_single() error in e1000_tx_map */ | 4139 | e1000_tx_queue(adapter, tx_flags, count); |
4140 | netdev->trans_start = jiffies; | ||
4141 | /* Make sure there is space in the ring for the next send. */ | ||
4142 | e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); | ||
4143 | |||
4144 | } else { | ||
4151 | dev_kfree_skb_any(skb); | 4145 | dev_kfree_skb_any(skb); |
4152 | return NETDEV_TX_OK; | 4146 | tx_ring->buffer_info[first].time_stamp = 0; |
4147 | tx_ring->next_to_use = first; | ||
4153 | } | 4148 | } |
4154 | 4149 | ||
4155 | e1000_tx_queue(adapter, tx_flags, count); | ||
4156 | |||
4157 | netdev->trans_start = jiffies; | ||
4158 | |||
4159 | /* Make sure there is space in the ring for the next send. */ | ||
4160 | e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); | ||
4161 | |||
4162 | return NETDEV_TX_OK; | 4150 | return NETDEV_TX_OK; |
4163 | } | 4151 | } |
4164 | 4152 | ||