diff options
author | Huang, Xiong <xiong@qca.qualcomm.com> | 2013-02-11 09:44:40 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-13 13:32:37 -0500 |
commit | ac574804d412047e52de4dd887615cc88f58aeb0 (patch) | |
tree | fb7472fb24ab92117a4621c449efbb90da02ed17 /drivers | |
parent | 9c10f4115cc3722635d6e277385ec96003281784 (diff) |
atl1c: add error checking for pci_map_single functions
it is reported that code hit DMA-API errors on 3.8-rc6+,
(see https://bugzilla.redhat.com/show_bug.cgi?id=908436, and
https://bugzilla.redhat.com/show_bug.cgi?id=908550)
this patch just adds error handler for
pci_map_single and skb_frag_dma_map.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 71 |
1 files changed, 64 insertions, 7 deletions
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 56d3f697e0c7..0035c01660b6 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | #include "atl1c.h" | 22 | #include "atl1c.h" |
23 | 23 | ||
24 | #define ATL1C_DRV_VERSION "1.0.1.0-NAPI" | 24 | #define ATL1C_DRV_VERSION "1.0.1.1-NAPI" |
25 | char atl1c_driver_name[] = "atl1c"; | 25 | char atl1c_driver_name[] = "atl1c"; |
26 | char atl1c_driver_version[] = ATL1C_DRV_VERSION; | 26 | char atl1c_driver_version[] = ATL1C_DRV_VERSION; |
27 | 27 | ||
@@ -1652,6 +1652,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) | |||
1652 | u16 num_alloc = 0; | 1652 | u16 num_alloc = 0; |
1653 | u16 rfd_next_to_use, next_next; | 1653 | u16 rfd_next_to_use, next_next; |
1654 | struct atl1c_rx_free_desc *rfd_desc; | 1654 | struct atl1c_rx_free_desc *rfd_desc; |
1655 | dma_addr_t mapping; | ||
1655 | 1656 | ||
1656 | next_next = rfd_next_to_use = rfd_ring->next_to_use; | 1657 | next_next = rfd_next_to_use = rfd_ring->next_to_use; |
1657 | if (++next_next == rfd_ring->count) | 1658 | if (++next_next == rfd_ring->count) |
@@ -1678,9 +1679,18 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) | |||
1678 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 1679 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); |
1679 | buffer_info->skb = skb; | 1680 | buffer_info->skb = skb; |
1680 | buffer_info->length = adapter->rx_buffer_len; | 1681 | buffer_info->length = adapter->rx_buffer_len; |
1681 | buffer_info->dma = pci_map_single(pdev, vir_addr, | 1682 | mapping = pci_map_single(pdev, vir_addr, |
1682 | buffer_info->length, | 1683 | buffer_info->length, |
1683 | PCI_DMA_FROMDEVICE); | 1684 | PCI_DMA_FROMDEVICE); |
1685 | if (unlikely(pci_dma_mapping_error(pdev, mapping))) { | ||
1686 | dev_kfree_skb(skb); | ||
1687 | buffer_info->skb = NULL; | ||
1688 | buffer_info->length = 0; | ||
1689 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); | ||
1690 | netif_warn(adapter, rx_err, adapter->netdev, "RX pci_map_single failed"); | ||
1691 | break; | ||
1692 | } | ||
1693 | buffer_info->dma = mapping; | ||
1684 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, | 1694 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, |
1685 | ATL1C_PCIMAP_FROMDEVICE); | 1695 | ATL1C_PCIMAP_FROMDEVICE); |
1686 | rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); | 1696 | rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); |
@@ -2015,7 +2025,29 @@ check_sum: | |||
2015 | return 0; | 2025 | return 0; |
2016 | } | 2026 | } |
2017 | 2027 | ||
2018 | static void atl1c_tx_map(struct atl1c_adapter *adapter, | 2028 | static void atl1c_tx_rollback(struct atl1c_adapter *adpt, |
2029 | struct atl1c_tpd_desc *first_tpd, | ||
2030 | enum atl1c_trans_queue type) | ||
2031 | { | ||
2032 | struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[type]; | ||
2033 | struct atl1c_buffer *buffer_info; | ||
2034 | struct atl1c_tpd_desc *tpd; | ||
2035 | u16 first_index, index; | ||
2036 | |||
2037 | first_index = first_tpd - (struct atl1c_tpd_desc *)tpd_ring->desc; | ||
2038 | index = first_index; | ||
2039 | while (index != tpd_ring->next_to_use) { | ||
2040 | tpd = ATL1C_TPD_DESC(tpd_ring, index); | ||
2041 | buffer_info = &tpd_ring->buffer_info[index]; | ||
2042 | atl1c_clean_buffer(adpt->pdev, buffer_info, 0); | ||
2043 | memset(tpd, 0, sizeof(struct atl1c_tpd_desc)); | ||
2044 | if (++index == tpd_ring->count) | ||
2045 | index = 0; | ||
2046 | } | ||
2047 | tpd_ring->next_to_use = first_index; | ||
2048 | } | ||
2049 | |||
2050 | static int atl1c_tx_map(struct atl1c_adapter *adapter, | ||
2019 | struct sk_buff *skb, struct atl1c_tpd_desc *tpd, | 2051 | struct sk_buff *skb, struct atl1c_tpd_desc *tpd, |
2020 | enum atl1c_trans_queue type) | 2052 | enum atl1c_trans_queue type) |
2021 | { | 2053 | { |
@@ -2040,7 +2072,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2040 | buffer_info->length = map_len; | 2072 | buffer_info->length = map_len; |
2041 | buffer_info->dma = pci_map_single(adapter->pdev, | 2073 | buffer_info->dma = pci_map_single(adapter->pdev, |
2042 | skb->data, hdr_len, PCI_DMA_TODEVICE); | 2074 | skb->data, hdr_len, PCI_DMA_TODEVICE); |
2043 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 2075 | if (unlikely(pci_dma_mapping_error(adapter->pdev, |
2076 | buffer_info->dma))) | ||
2077 | goto err_dma; | ||
2078 | |||
2044 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, | 2079 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, |
2045 | ATL1C_PCIMAP_TODEVICE); | 2080 | ATL1C_PCIMAP_TODEVICE); |
2046 | mapped_len += map_len; | 2081 | mapped_len += map_len; |
@@ -2062,6 +2097,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2062 | buffer_info->dma = | 2097 | buffer_info->dma = |
2063 | pci_map_single(adapter->pdev, skb->data + mapped_len, | 2098 | pci_map_single(adapter->pdev, skb->data + mapped_len, |
2064 | buffer_info->length, PCI_DMA_TODEVICE); | 2099 | buffer_info->length, PCI_DMA_TODEVICE); |
2100 | if (unlikely(pci_dma_mapping_error(adapter->pdev, | ||
2101 | buffer_info->dma))) | ||
2102 | goto err_dma; | ||
2103 | |||
2065 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 2104 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); |
2066 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, | 2105 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, |
2067 | ATL1C_PCIMAP_TODEVICE); | 2106 | ATL1C_PCIMAP_TODEVICE); |
@@ -2083,6 +2122,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2083 | frag, 0, | 2122 | frag, 0, |
2084 | buffer_info->length, | 2123 | buffer_info->length, |
2085 | DMA_TO_DEVICE); | 2124 | DMA_TO_DEVICE); |
2125 | if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) | ||
2126 | goto err_dma; | ||
2127 | |||
2086 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 2128 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); |
2087 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE, | 2129 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE, |
2088 | ATL1C_PCIMAP_TODEVICE); | 2130 | ATL1C_PCIMAP_TODEVICE); |
@@ -2095,6 +2137,13 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2095 | /* The last buffer info contain the skb address, | 2137 | /* The last buffer info contain the skb address, |
2096 | so it will be free after unmap */ | 2138 | so it will be free after unmap */ |
2097 | buffer_info->skb = skb; | 2139 | buffer_info->skb = skb; |
2140 | |||
2141 | return 0; | ||
2142 | |||
2143 | err_dma: | ||
2144 | buffer_info->dma = 0; | ||
2145 | buffer_info->length = 0; | ||
2146 | return -1; | ||
2098 | } | 2147 | } |
2099 | 2148 | ||
2100 | static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, | 2149 | static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, |
@@ -2157,10 +2206,18 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, | |||
2157 | if (skb_network_offset(skb) != ETH_HLEN) | 2206 | if (skb_network_offset(skb) != ETH_HLEN) |
2158 | tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */ | 2207 | tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */ |
2159 | 2208 | ||
2160 | atl1c_tx_map(adapter, skb, tpd, type); | 2209 | if (atl1c_tx_map(adapter, skb, tpd, type) < 0) { |
2161 | atl1c_tx_queue(adapter, skb, tpd, type); | 2210 | netif_info(adapter, tx_done, adapter->netdev, |
2211 | "tx-skb droppted due to dma error\n"); | ||
2212 | /* roll back tpd/buffer */ | ||
2213 | atl1c_tx_rollback(adapter, tpd, type); | ||
2214 | spin_unlock_irqrestore(&adapter->tx_lock, flags); | ||
2215 | dev_kfree_skb(skb); | ||
2216 | } else { | ||
2217 | atl1c_tx_queue(adapter, skb, tpd, type); | ||
2218 | spin_unlock_irqrestore(&adapter->tx_lock, flags); | ||
2219 | } | ||
2162 | 2220 | ||
2163 | spin_unlock_irqrestore(&adapter->tx_lock, flags); | ||
2164 | return NETDEV_TX_OK; | 2221 | return NETDEV_TX_OK; |
2165 | } | 2222 | } |
2166 | 2223 | ||