Commit 584ec435 authored by Neil Horman's avatar Neil Horman Committed by David S. Miller

atl1e: unmap partially mapped skb on dma error and free skb

Ben Hutchings pointed out that my recent update to atl1e
in commit 352900b5
("atl1e: fix dma mapping warnings") was missing a bit of code.

Specifically it reset the hardware tx ring to its origional state when
we hit a dma error, but didn't unmap any exiting mappings from the
operation.  This patch fixes that up.  It also remembers to free the
skb in the event that an error occurs, so we don't leak.  Untested, as
I don't have hardware.  I think its pretty straightforward, but please
review closely.
Signed-off-by: default avatarNeil Horman <nhorman@tuxdriver.com>
CC: Ben Hutchings <bhutchings@solarflare.com>
CC: Jay Cliburn <jcliburn@gmail.com>
CC: Chris Snook <chris.snook@gmail.com>
CC: "David S. Miller" <davem@davemloft.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 47188d39
...@@ -1678,6 +1678,7 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter, ...@@ -1678,6 +1678,7 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter,
u16 f; u16 f;
int segment; int segment;
int ring_start = adapter->tx_ring.next_to_use; int ring_start = adapter->tx_ring.next_to_use;
int ring_end;
nr_frags = skb_shinfo(skb)->nr_frags; nr_frags = skb_shinfo(skb)->nr_frags;
segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK; segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK;
...@@ -1721,6 +1722,15 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter, ...@@ -1721,6 +1722,15 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter,
map_len, PCI_DMA_TODEVICE); map_len, PCI_DMA_TODEVICE);
if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) { if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) {
/* We need to unwind the mappings we've done */
ring_end = adapter->tx_ring.next_to_use;
adapter->tx_ring.next_to_use = ring_start;
while (adapter->tx_ring.next_to_use != ring_end) {
tpd = atl1e_get_tpd(adapter);
tx_buffer = atl1e_get_tx_buffer(adapter, tpd);
pci_unmap_single(adapter->pdev, tx_buffer->dma,
tx_buffer->length, PCI_DMA_TODEVICE);
}
/* Reset the tx rings next pointer */ /* Reset the tx rings next pointer */
adapter->tx_ring.next_to_use = ring_start; adapter->tx_ring.next_to_use = ring_start;
return -ENOSPC; return -ENOSPC;
...@@ -1763,6 +1773,16 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter, ...@@ -1763,6 +1773,16 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter,
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) { if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) {
/* We need to unwind the mappings we've done */
ring_end = adapter->tx_ring.next_to_use;
adapter->tx_ring.next_to_use = ring_start;
while (adapter->tx_ring.next_to_use != ring_end) {
tpd = atl1e_get_tpd(adapter);
tx_buffer = atl1e_get_tx_buffer(adapter, tpd);
dma_unmap_page(&adapter->pdev->dev, tx_buffer->dma,
tx_buffer->length, DMA_TO_DEVICE);
}
/* Reset the ring next to use pointer */ /* Reset the ring next to use pointer */
adapter->tx_ring.next_to_use = ring_start; adapter->tx_ring.next_to_use = ring_start;
return -ENOSPC; return -ENOSPC;
...@@ -1853,8 +1873,10 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb, ...@@ -1853,8 +1873,10 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
if (atl1e_tx_map(adapter, skb, tpd)) if (atl1e_tx_map(adapter, skb, tpd)) {
dev_kfree_skb_any(skb);
goto out; goto out;
}
atl1e_tx_queue(adapter, tpd_req, tpd); atl1e_tx_queue(adapter, tpd_req, tpd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment