Skip to content

Commit

Permalink
e1000: fix unmap bug
Browse files Browse the repository at this point in the history
This is in reference to the issue shown in kerneloops (search e1000 unmap)

The e1000 transmit code was calling pci_unmap_page on dma handles that it
might have called pci_map_single on.

Same bug as e1000e

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Acked-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jesse Brandeburg authored and David S. Miller committed Mar 3, 2009
1 parent 8ddc951 commit d20b606
Showing 1 changed file with 27 additions and 24 deletions.
51 changes: 27 additions & 24 deletions drivers/net/e1000/e1000_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2049,14 +2049,10 @@ void e1000_free_all_tx_resources(struct e1000_adapter *adapter)
static void e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info)
{
if (buffer_info->dma) {
pci_unmap_page(adapter->pdev,
buffer_info->dma,
buffer_info->length,
PCI_DMA_TODEVICE);
buffer_info->dma = 0;
}
buffer_info->dma = 0;
if (buffer_info->skb) {
skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb,
DMA_TO_DEVICE);
dev_kfree_skb_any(buffer_info->skb);
buffer_info->skb = NULL;
}
Expand Down Expand Up @@ -2907,16 +2903,24 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
unsigned int mss)
{
struct e1000_hw *hw = &adapter->hw;
struct e1000_buffer *buffer_info;
unsigned int len = skb->len;
unsigned int offset = 0, size, count = 0, i;
unsigned int len = skb_headlen(skb);
unsigned int offset, size, count = 0, i;
unsigned int f;
len -= skb->data_len;
dma_addr_t map;

i = tx_ring->next_to_use;

if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) {
dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
dev_kfree_skb(skb);
return -2;
}

map = skb_shinfo(skb)->dma_maps[0];
offset = 0;

while (len) {
buffer_info = &tx_ring->buffer_info[i];
struct e1000_buffer *buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
/* Workaround for Controller erratum --
* descriptor for non-tso packet in a linear SKB that follows a
Expand Down Expand Up @@ -2949,11 +2953,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
size -= 4;

buffer_info->length = size;
buffer_info->dma =
pci_map_single(adapter->pdev,
skb->data + offset,
size,
PCI_DMA_TODEVICE);
buffer_info->dma = map + offset;
buffer_info->time_stamp = jiffies;
buffer_info->next_to_watch = i;

Expand All @@ -2968,9 +2968,11 @@ static int e1000_tx_map(struct e1000_adapter *adapter,

frag = &skb_shinfo(skb)->frags[f];
len = frag->size;
offset = frag->page_offset;
map = skb_shinfo(skb)->dma_maps[f + 1];
offset = 0;

while (len) {
struct e1000_buffer *buffer_info;
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
/* Workaround for premature desc write-backs
Expand All @@ -2986,12 +2988,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
size -= 4;

buffer_info->length = size;
buffer_info->dma =
pci_map_page(adapter->pdev,
frag->page,
offset,
size,
PCI_DMA_TODEVICE);
buffer_info->dma = map + offset;
buffer_info->time_stamp = jiffies;
buffer_info->next_to_watch = i;

Expand All @@ -3005,6 +3002,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
i = (i == 0) ? tx_ring->count - 1 : i - 1;
tx_ring->buffer_info[i].skb = skb;
tx_ring->buffer_info[first].next_to_watch = i;
smp_wmb();

return count;
}
Expand Down Expand Up @@ -3844,6 +3842,11 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
/* Detect a transmit hang in hardware, this serializes the
* check with the clearing of time_stamp and movement of i */
adapter->detect_tx_hung = false;
/*
* read barrier to make sure that the ->dma member and time
* stamp are updated fully
*/
smp_rmb();
if (tx_ring->buffer_info[eop].dma &&
time_after(jiffies, tx_ring->buffer_info[eop].time_stamp +
(adapter->tx_timeout_factor * HZ))
Expand Down

0 comments on commit d20b606

Please sign in to comment.