summaryrefslogtreecommitdiff
path: root/debian/patches/libdde_trans_start.patch
blob: 9b0330a7b0d361cb2aa3ab7a6742cd2edcc65d07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
commit 9d21493b4beb8f918ba248032fefa393074a5e2b
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Sun May 17 20:55:16 2009 -0700

    net: tx scalability works : trans_start
    
    struct net_device trans_start field is a hot spot on SMP and high performance
    devices, particularly multi queues ones, because every transmitter dirties
    it. Is main use is tx watchdog and bonding alive checks.
    
    But as most devices dont use NETIF_F_LLTX, we have to lock
    a netdev_queue before calling their ndo_start_xmit(). So it makes
    sense to move trans_start from net_device to netdev_queue. Its update
    will occur on a already present (and in exclusive state) cache line, for
    free.
    
    We can do this transition smoothly. An old driver continue to
    update dev->trans_start, while an updated one updates txq->trans_start.
    
    Further patches could also put tx_bytes/tx_packets counters in
    netdev_queue to avoid dirtying dev->stats (vlan device comes to mind)
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Index: hurd-debian/libdde-linux26/contrib/include/linux/netdevice.h
===================================================================
--- hurd-debian.orig/libdde-linux26/contrib/include/linux/netdevice.h	2012-04-16 00:34:54.000000000 +0000
+++ hurd-debian/libdde-linux26/contrib/include/linux/netdevice.h	2012-04-16 00:35:04.000000000 +0000
@@ -462,6 +462,10 @@
 	spinlock_t		_xmit_lock;
 	int			xmit_lock_owner;
 	struct Qdisc		*qdisc_sleeping;
+	/*
+	 * please use this field instead of dev->trans_start
+	 */
+	unsigned long		trans_start;
 } ____cacheline_aligned_in_smp;
 
 
@@ -801,6 +805,11 @@
  * One part is mostly used on xmit path (device)
  */
 	/* These may be needed for future network-power-down code. */
+
+	/*
+	 * trans_start here is expensive for high speed devices on SMP,
+	 * please use netdev_queue->trans_start instead.
+	 */
 	unsigned long		trans_start;	/* Time (in jiffies) of last Tx	*/
 
 	int			watchdog_timeo; /* used by dev_watchdog() */
@@ -1477,6 +1486,8 @@
 	return !test_bit(__LINK_STATE_NOCARRIER, &dev->state);
 }
 
+extern unsigned long dev_trans_start(struct net_device *dev);
+
 extern void __netdev_watchdog_up(struct net_device *dev);
 
 extern void netif_carrier_on(struct net_device *dev);
Index: hurd-debian/libdde-linux26/lib/src/net/sched/sch_generic.c
===================================================================
--- hurd-debian.orig/libdde-linux26/lib/src/net/sched/sch_generic.c	2012-04-16 00:26:38.000000000 +0000
+++ hurd-debian/libdde-linux26/lib/src/net/sched/sch_generic.c	2012-04-16 00:35:04.000000000 +0000
@@ -200,6 +200,21 @@
 	clear_bit(__QDISC_STATE_RUNNING, &q->state);
 }
 
+unsigned long dev_trans_start(struct net_device *dev)
+{
+	unsigned long val, res = dev->trans_start;
+	unsigned int i;
+
+	for (i = 0; i < dev->num_tx_queues; i++) {
+		val = netdev_get_tx_queue(dev, i)->trans_start;
+		if (val && time_after(val, res))
+			res = val;
+	}
+	dev->trans_start = res;
+	return res;
+}
+EXPORT_SYMBOL(dev_trans_start);
+
 static void dev_watchdog(unsigned long arg)
 {
 	struct net_device *dev = (struct net_device *)arg;
@@ -209,25 +224,30 @@
 		if (netif_device_present(dev) &&
 		    netif_running(dev) &&
 		    netif_carrier_ok(dev)) {
-			int some_queue_stopped = 0;
+			int some_queue_timedout = 0;
 			unsigned int i;
+			unsigned long trans_start;
 
 			for (i = 0; i < dev->num_tx_queues; i++) {
 				struct netdev_queue *txq;
 
 				txq = netdev_get_tx_queue(dev, i);
-				if (netif_tx_queue_stopped(txq)) {
-					some_queue_stopped = 1;
+				/*
+				 * old device drivers set dev->trans_start
+				 */
+				trans_start = txq->trans_start ? : dev->trans_start;
+				if (netif_tx_queue_stopped(txq) &&
+				    time_after(jiffies, (trans_start +
+							 dev->watchdog_timeo))) {
+					some_queue_timedout = 1;
 					break;
 				}
 			}
 
-			if (some_queue_stopped &&
-			    time_after(jiffies, (dev->trans_start +
-						 dev->watchdog_timeo))) {
+			if (some_queue_timedout) {
 				char drivername[64];
-				WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
-				       dev->name, netdev_drivername(dev, drivername, 64));
+				WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n",
+				       dev->name, netdev_drivername(dev, drivername, 64), i);
 				dev->netdev_ops->ndo_tx_timeout(dev);
 			}
 			if (!mod_timer(&dev->watchdog_timer,
@@ -612,8 +632,10 @@
 		clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state);
 
 	rcu_assign_pointer(dev_queue->qdisc, new_qdisc);
-	if (need_watchdog_p && new_qdisc != &noqueue_qdisc)
+	if (need_watchdog_p && new_qdisc != &noqueue_qdisc) {
+		dev_queue->trans_start = 0;
 		*need_watchdog_p = 1;
+	}
 }
 
 void dev_activate(struct net_device *dev)