diff options
author | Rob Herring <rob.herring@calxeda.com> | 2013-08-30 17:49:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-09-03 22:21:16 -0400 |
commit | 92cd4253e553e87a715243a36623945edcbf1ec7 (patch) | |
tree | 46ca3c346fc1a1d5f53e76d3a34fee54018e5362 /drivers/net | |
parent | 531cda20cd44d5a7a77debaaeaa407d4802d7e05 (diff) |
net: calxedaxgmac: fix xgmac_xmit DMA mapping error handling
On a DMA mapping error in xgmac_xmit, we should simply free the skb and
return NETDEV_TX_OK rather than -EIO. In the case of errors in mapping
frags, we need to undo everything that has been setup.
Reported-by: Andreas Herrmann <andreas.herrmann@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/calxeda/xgmac.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index cd5010b4a89c..78d6d6b970e1 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c | |||
@@ -466,6 +466,13 @@ static inline void desc_set_tx_owner(struct xgmac_dma_desc *p, u32 flags) | |||
466 | p->flags = cpu_to_le32(tmpflags); | 466 | p->flags = cpu_to_le32(tmpflags); |
467 | } | 467 | } |
468 | 468 | ||
469 | static inline void desc_clear_tx_owner(struct xgmac_dma_desc *p) | ||
470 | { | ||
471 | u32 tmpflags = le32_to_cpu(p->flags); | ||
472 | tmpflags &= TXDESC_END_RING; | ||
473 | p->flags = cpu_to_le32(tmpflags); | ||
474 | } | ||
475 | |||
469 | static inline int desc_get_tx_ls(struct xgmac_dma_desc *p) | 476 | static inline int desc_get_tx_ls(struct xgmac_dma_desc *p) |
470 | { | 477 | { |
471 | return le32_to_cpu(p->flags) & TXDESC_LAST_SEG; | 478 | return le32_to_cpu(p->flags) & TXDESC_LAST_SEG; |
@@ -1100,7 +1107,7 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1100 | paddr = dma_map_single(priv->device, skb->data, len, DMA_TO_DEVICE); | 1107 | paddr = dma_map_single(priv->device, skb->data, len, DMA_TO_DEVICE); |
1101 | if (dma_mapping_error(priv->device, paddr)) { | 1108 | if (dma_mapping_error(priv->device, paddr)) { |
1102 | dev_kfree_skb(skb); | 1109 | dev_kfree_skb(skb); |
1103 | return -EIO; | 1110 | return NETDEV_TX_OK; |
1104 | } | 1111 | } |
1105 | priv->tx_skbuff[entry] = skb; | 1112 | priv->tx_skbuff[entry] = skb; |
1106 | desc_set_buf_addr_and_size(desc, paddr, len); | 1113 | desc_set_buf_addr_and_size(desc, paddr, len); |
@@ -1112,10 +1119,8 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1112 | 1119 | ||
1113 | paddr = skb_frag_dma_map(priv->device, frag, 0, len, | 1120 | paddr = skb_frag_dma_map(priv->device, frag, 0, len, |
1114 | DMA_TO_DEVICE); | 1121 | DMA_TO_DEVICE); |
1115 | if (dma_mapping_error(priv->device, paddr)) { | 1122 | if (dma_mapping_error(priv->device, paddr)) |
1116 | dev_kfree_skb(skb); | 1123 | goto dma_err; |
1117 | return -EIO; | ||
1118 | } | ||
1119 | 1124 | ||
1120 | entry = dma_ring_incr(entry, DMA_TX_RING_SZ); | 1125 | entry = dma_ring_incr(entry, DMA_TX_RING_SZ); |
1121 | desc = priv->dma_tx + entry; | 1126 | desc = priv->dma_tx + entry; |
@@ -1151,6 +1156,22 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1151 | netif_start_queue(dev); | 1156 | netif_start_queue(dev); |
1152 | } | 1157 | } |
1153 | return NETDEV_TX_OK; | 1158 | return NETDEV_TX_OK; |
1159 | |||
1160 | dma_err: | ||
1161 | entry = priv->tx_head; | ||
1162 | for ( ; i > 0; i--) { | ||
1163 | entry = dma_ring_incr(entry, DMA_TX_RING_SZ); | ||
1164 | desc = priv->dma_tx + entry; | ||
1165 | priv->tx_skbuff[entry] = NULL; | ||
1166 | dma_unmap_page(priv->device, desc_get_buf_addr(desc), | ||
1167 | desc_get_buf_len(desc), DMA_TO_DEVICE); | ||
1168 | desc_clear_tx_owner(desc); | ||
1169 | } | ||
1170 | desc = first; | ||
1171 | dma_unmap_single(priv->device, desc_get_buf_addr(desc), | ||
1172 | desc_get_buf_len(desc), DMA_TO_DEVICE); | ||
1173 | dev_kfree_skb(skb); | ||
1174 | return NETDEV_TX_OK; | ||
1154 | } | 1175 | } |
1155 | 1176 | ||
1156 | static int xgmac_rx(struct xgmac_priv *priv, int limit) | 1177 | static int xgmac_rx(struct xgmac_priv *priv, int limit) |