aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/e1000
diff options
context:
space:
mode:
authorDean Nelson <dnelson@redhat.com>2011-08-25 10:39:24 -0400
committerDavid S. Miller <davem@davemloft.net>2011-08-26 12:55:18 -0400
commit31c15a2f24ebdab14333d9bf5df49757842ae2ec (patch)
treeef89d4b94c4f41f6d18c923490441189ff95b52d /drivers/net/ethernet/intel/e1000
parent363437f40a23bacdead80bb80d08d8193a20cfce (diff)
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 9ed318d546a29d7a591dbe648fd1a2efe3be1180 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: Dean Nelson <dnelson@redhat.com> Acked-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/intel/e1000')
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000.h2
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c18
2 files changed, 11 insertions, 9 deletions
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 24f41da8c4be..4ea87b19ac1a 100644
--- a/drivers/net/ethernet/intel/e1000/e1000.h
+++ b/drivers/net/ethernet/intel/e1000/e1000.h
@@ -150,6 +150,8 @@ struct e1000_buffer {
150 unsigned long time_stamp; 150 unsigned long time_stamp;
151 u16 length; 151 u16 length;
152 u16 next_to_watch; 152 u16 next_to_watch;
153 unsigned int segs;
154 unsigned int bytecount;
153 u16 mapped_as_page; 155 u16 mapped_as_page;
154}; 156};
155 157
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 7c280e5832b2..4a32c15524c9 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -2848,7 +2848,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
2848 struct e1000_buffer *buffer_info; 2848 struct e1000_buffer *buffer_info;
2849 unsigned int len = skb_headlen(skb); 2849 unsigned int len = skb_headlen(skb);
2850 unsigned int offset = 0, size, count = 0, i; 2850 unsigned int offset = 0, size, count = 0, i;
2851 unsigned int f; 2851 unsigned int f, bytecount, segs;
2852 2852
2853 i = tx_ring->next_to_use; 2853 i = tx_ring->next_to_use;
2854 2854
@@ -2949,7 +2949,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
2949 } 2949 }
2950 } 2950 }
2951 2951
2952 segs = skb_shinfo(skb)->gso_segs ?: 1;
2953 /* multiply data chunks by size of headers */
2954 bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
2955
2952 tx_ring->buffer_info[i].skb = skb; 2956 tx_ring->buffer_info[i].skb = skb;
2957 tx_ring->buffer_info[i].segs = segs;
2958 tx_ring->buffer_info[i].bytecount = bytecount;
2953 tx_ring->buffer_info[first].next_to_watch = i; 2959 tx_ring->buffer_info[first].next_to_watch = i;
2954 2960
2955 return count; 2961 return count;
@@ -3623,14 +3629,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
3623 cleaned = (i == eop); 3629 cleaned = (i == eop);
3624 3630
3625 if (cleaned) { 3631 if (cleaned) {
3626 struct sk_buff *skb = buffer_info->skb; 3632 total_tx_packets += buffer_info->segs;
3627 unsigned int segs, bytecount; 3633 total_tx_bytes += buffer_info->bytecount;
3628 segs = skb_shinfo(skb)->gso_segs ?: 1;
3629 /* multiply data chunks by size of headers */
3630 bytecount = ((segs - 1) * skb_headlen(skb)) +
3631 skb->len;
3632 total_tx_packets += segs;
3633 total_tx_bytes += bytecount;
3634 } 3634 }
3635 e1000_unmap_and_free_tx_resource(adapter, buffer_info); 3635 e1000_unmap_and_free_tx_resource(adapter, buffer_info);
3636 tx_desc->upper.data = 0; 3636 tx_desc->upper.data = 0;