|
@@ -1678,6 +1678,7 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter,
|
|
|
u16 f;
|
|
|
int segment;
|
|
|
int ring_start = adapter->tx_ring.next_to_use;
|
|
|
+ int ring_end;
|
|
|
|
|
|
nr_frags = skb_shinfo(skb)->nr_frags;
|
|
|
segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK;
|
|
@@ -1721,6 +1722,15 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter,
|
|
|
map_len, PCI_DMA_TODEVICE);
|
|
|
|
|
|
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 */
|
|
|
adapter->tx_ring.next_to_use = ring_start;
|
|
|
return -ENOSPC;
|
|
@@ -1763,6 +1773,16 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter,
|
|
|
DMA_TO_DEVICE);
|
|
|
|
|
|
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 */
|
|
|
adapter->tx_ring.next_to_use = ring_start;
|
|
|
return -ENOSPC;
|
|
@@ -1853,8 +1873,10 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb,
|
|
|
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;
|
|
|
+ }
|
|
|
|
|
|
atl1e_tx_queue(adapter, tpd_req, tpd);
|
|
|
|