*/
bond_for_each_slave(bond, slave, i) {
if (slave->link != BOND_LINK_UP) {
- if (time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks) &&
+ if (time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks) &&
time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) {
slave->link = BOND_LINK_UP;
* when the source ip is 0, so don't take the link down
* if we don't know our ip yet
*/
- if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
+ if (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2*delta_in_ticks) ||
(time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) {
slave->link = BOND_LINK_DOWN;
* the bond has an IP address)
*/
if ((slave->state == BOND_STATE_ACTIVE) &&
- (time_after_eq(jiffies, slave->dev->trans_start +
+ (time_after_eq(jiffies, dev_trans_start(slave->dev) +
2 * delta_in_ticks) ||
(time_after_eq(jiffies, slave_last_rx(bond, slave)
+ 2 * delta_in_ticks)))) {
write_lock_bh(&bond->curr_slave_lock);
if (!bond->curr_active_slave &&
- time_before_eq(jiffies, slave->dev->trans_start +
+ time_before_eq(jiffies, dev_trans_start(slave->dev) +
delta_in_ticks)) {
slave->link = BOND_LINK_UP;
bond_change_active_slave(bond, slave);
*/
spinlock_t _xmit_lock ____cacheline_aligned_in_smp;
int xmit_lock_owner;
+ /*
+ * please use this field instead of dev->trans_start
+ */
+ unsigned long trans_start;
} ____cacheline_aligned_in_smp;
* 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() */
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);
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;
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,
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)