aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000
diff options
context:
space:
mode:
authorDean Nelson <dnelson@redhat.com>2011-08-25 10:39:24 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-17 14:23:12 -0400
commit52f81dc563e58bfbd22f1b0e2037da855a26b995 (patch)
treead7639a67063f73d48f9a5be9e990e3c91790ac5 /drivers/net/e1000
parent6140710c5dba509a20b26dfe38b58f40baf2a2c8 (diff)
e1000: save skb counts in TX to avoid cache misses
commit 31c15a2f24ebdab14333d9bf5df49757842ae2ec upstream. 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> Signed-off-by: Roman Kagan <rkagan@parallels.com>
Diffstat (limited to 'drivers/net/e1000')
-rw-r--r--drivers/net/e1000/e1000.h2
-rw-r--r--drivers/net/e1000/e1000_main.c18
2 files changed, 11 insertions, 9 deletions
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 8676899120c..2c71884eb46 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/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/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 76e8af00d86..99525f9b41b 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2798,7 +2798,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
2798 struct e1000_buffer *buffer_info; 2798 struct e1000_buffer *buffer_info;
2799 unsigned int len = skb_headlen(skb); 2799 unsigned int len = skb_headlen(skb);
2800 unsigned int offset = 0, size, count = 0, i; 2800 unsigned int offset = 0, size, count = 0, i;
2801 unsigned int f; 2801 unsigned int f, bytecount, segs;
2802 2802
2803 i = tx_ring->next_to_use; 2803 i = tx_ring->next_to_use;
2804 2804
@@ -2899,7 +2899,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
2899 } 2899 }
2900 } 2900 }
2901 2901
2902 segs = skb_shinfo(skb)->gso_segs ?: 1;
2903 /* multiply data chunks by size of headers */
2904 bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
2905
2902 tx_ring->buffer_info[i].skb = skb; 2906 tx_ring->buffer_info[i].skb = skb;
2907 tx_ring->buffer_info[i].segs = segs;
2908 tx_ring->buffer_info[i].bytecount = bytecount;
2903 tx_ring->buffer_info[first].next_to_watch = i; 2909 tx_ring->buffer_info[first].next_to_watch = i;
2904 2910
2905 return count; 2911 return count;
@@ -3573,14 +3579,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
3573 cleaned = (i == eop); 3579 cleaned = (i == eop);
3574 3580
3575 if (cleaned) { 3581 if (cleaned) {
3576 struct sk_buff *skb = buffer_info->skb; 3582 total_tx_packets += buffer_info->segs;
3577 unsigned int segs, bytecount; 3583 total_tx_bytes += buffer_info->bytecount;
3578 segs = skb_shinfo(skb)->gso_segs ?: 1;
3579 /* multiply data chunks by size of headers */
3580 bytecount = ((segs - 1) * skb_headlen(skb)) +
3581 skb->len;
3582 total_tx_packets += segs;
3583 total_tx_bytes += bytecount;
3584 } 3584 }
3585 e1000_unmap_and_free_tx_resource(adapter, buffer_info); 3585 e1000_unmap_and_free_tx_resource(adapter, buffer_info);
3586 tx_desc->upper.data = 0; 3586 tx_desc->upper.data = 0;