aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRob Herring <rob.herring@calxeda.com>2013-08-30 17:49:29 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-03 22:21:16 -0400
commit92cd4253e553e87a715243a36623945edcbf1ec7 (patch)
tree46ca3c346fc1a1d5f53e76d3a34fee54018e5362 /drivers/net
parent531cda20cd44d5a7a77debaaeaa407d4802d7e05 (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.c31
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
469static 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
469static inline int desc_get_tx_ls(struct xgmac_dma_desc *p) 476static 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
1160dma_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
1156static int xgmac_rx(struct xgmac_priv *priv, int limit) 1177static int xgmac_rx(struct xgmac_priv *priv, int limit)