Commit 31c15a2f authored by Dean Nelson's avatar Dean Nelson Committed by David S. Miller

e1000: save skb counts in TX to avoid cache misses

Virtual Machines with emulated e1000 network adapter running on Parallels'
server were seeing kernel panics due to the e1000 driver dereferencing an
unexpected NULL pointer retrieved from buffer_info->skb.

The problem has been addressed for the e1000e driver, but not for the e1000.
Since the two drivers share similar code in the affected area, a port of the
following e1000e driver commit solves the issue for the e1000 driver:

commit 9ed318d5
Author: Tom Herbert <therbert@google.com>
Date:   Wed May 5 14:02:27 2010 +0000

    e1000e: save skb counts in TX to avoid cache misses

    In e1000_tx_map, precompute number of segements and bytecounts which
    are derived from fields in skb; these are stored in buffer_info.  When
    cleaning tx in e1000_clean_tx_irq use the values in the associated
    buffer_info for statistics counting, this eliminates cache misses
    on skb fields.
Signed-off-by: default avatarDean Nelson <dnelson@redhat.com>
Acked-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 363437f4
...@@ -150,6 +150,8 @@ struct e1000_buffer { ...@@ -150,6 +150,8 @@ struct e1000_buffer {
unsigned long time_stamp; unsigned long time_stamp;
u16 length; u16 length;
u16 next_to_watch; u16 next_to_watch;
unsigned int segs;
unsigned int bytecount;
u16 mapped_as_page; u16 mapped_as_page;
}; };
......
...@@ -2848,7 +2848,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, ...@@ -2848,7 +2848,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info; struct e1000_buffer *buffer_info;
unsigned int len = skb_headlen(skb); unsigned int len = skb_headlen(skb);
unsigned int offset = 0, size, count = 0, i; unsigned int offset = 0, size, count = 0, i;
unsigned int f; unsigned int f, bytecount, segs;
i = tx_ring->next_to_use; i = tx_ring->next_to_use;
...@@ -2949,7 +2949,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter, ...@@ -2949,7 +2949,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
} }
} }
segs = skb_shinfo(skb)->gso_segs ?: 1;
/* multiply data chunks by size of headers */
bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[i].skb = skb;
tx_ring->buffer_info[i].segs = segs;
tx_ring->buffer_info[i].bytecount = bytecount;
tx_ring->buffer_info[first].next_to_watch = i; tx_ring->buffer_info[first].next_to_watch = i;
return count; return count;
...@@ -3623,14 +3629,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter, ...@@ -3623,14 +3629,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
cleaned = (i == eop); cleaned = (i == eop);
if (cleaned) { if (cleaned) {
struct sk_buff *skb = buffer_info->skb; total_tx_packets += buffer_info->segs;
unsigned int segs, bytecount; total_tx_bytes += buffer_info->bytecount;
segs = skb_shinfo(skb)->gso_segs ?: 1;
/* multiply data chunks by size of headers */
bytecount = ((segs - 1) * skb_headlen(skb)) +
skb->len;
total_tx_packets += segs;
total_tx_bytes += bytecount;
} }
e1000_unmap_and_free_tx_resource(adapter, buffer_info); e1000_unmap_and_free_tx_resource(adapter, buffer_info);
tx_desc->upper.data = 0; tx_desc->upper.data = 0;
......
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