ixgbe: fix bug when EITR=0 causing no writebacks

writebacks can be held indefinitely by hardware if EITR=0, when
combined with TXDCTL.WTHRESH=8.  When EITR=0, WTHRESH should be
set back to zero.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jesse Brandeburg 2010-04-27 01:37:41 +00:00 committed by David S. Miller
parent f8d1dcaf88
commit ef021194d2
2 changed files with 26 additions and 14 deletions

View File

@ -2083,7 +2083,7 @@ static int ixgbe_get_coalesce(struct net_device *netdev,
* this function must be called before setting the new value of * this function must be called before setting the new value of
* rx_itr_setting * rx_itr_setting
*/ */
static void ixgbe_reenable_rsc(struct ixgbe_adapter *adapter, static bool ixgbe_reenable_rsc(struct ixgbe_adapter *adapter,
struct ethtool_coalesce *ec) struct ethtool_coalesce *ec)
{ {
/* check the old value and enable RSC if necessary */ /* check the old value and enable RSC if necessary */
@ -2093,11 +2093,9 @@ static void ixgbe_reenable_rsc(struct ixgbe_adapter *adapter,
adapter->netdev->features |= NETIF_F_LRO; adapter->netdev->features |= NETIF_F_LRO;
DPRINTK(PROBE, INFO, "rx-usecs set to %d, re-enabling RSC\n", DPRINTK(PROBE, INFO, "rx-usecs set to %d, re-enabling RSC\n",
ec->rx_coalesce_usecs); ec->rx_coalesce_usecs);
if (netif_running(adapter->netdev)) return true;
ixgbe_reinit_locked(adapter);
else
ixgbe_reset(adapter);
} }
return false;
} }
static int ixgbe_set_coalesce(struct net_device *netdev, static int ixgbe_set_coalesce(struct net_device *netdev,
@ -2106,6 +2104,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_q_vector *q_vector; struct ixgbe_q_vector *q_vector;
int i; int i;
bool need_reset = false;
/* don't accept tx specific changes if we've got mixed RxTx vectors */ /* don't accept tx specific changes if we've got mixed RxTx vectors */
if (adapter->q_vector[0]->txr_count && adapter->q_vector[0]->rxr_count if (adapter->q_vector[0]->txr_count && adapter->q_vector[0]->rxr_count
@ -2128,7 +2127,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
return -EINVAL; return -EINVAL;
/* check the old value and enable RSC if necessary */ /* check the old value and enable RSC if necessary */
ixgbe_reenable_rsc(adapter, ec); need_reset = ixgbe_reenable_rsc(adapter, ec);
/* store the value in ints/second */ /* store the value in ints/second */
adapter->rx_eitr_param = 1000000/ec->rx_coalesce_usecs; adapter->rx_eitr_param = 1000000/ec->rx_coalesce_usecs;
@ -2139,7 +2138,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
adapter->rx_itr_setting &= ~1; adapter->rx_itr_setting &= ~1;
} else if (ec->rx_coalesce_usecs == 1) { } else if (ec->rx_coalesce_usecs == 1) {
/* check the old value and enable RSC if necessary */ /* check the old value and enable RSC if necessary */
ixgbe_reenable_rsc(adapter, ec); need_reset = ixgbe_reenable_rsc(adapter, ec);
/* 1 means dynamic mode */ /* 1 means dynamic mode */
adapter->rx_eitr_param = 20000; adapter->rx_eitr_param = 20000;
@ -2164,11 +2163,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
DPRINTK(PROBE, INFO, DPRINTK(PROBE, INFO,
"rx-usecs set to 0, disabling RSC\n"); "rx-usecs set to 0, disabling RSC\n");
if (netif_running(netdev)) need_reset = true;
ixgbe_reinit_locked(adapter);
else
ixgbe_reset(adapter);
return 0;
} }
} }
@ -2220,6 +2215,18 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
ixgbe_write_eitr(q_vector); ixgbe_write_eitr(q_vector);
} }
/*
* do reset here at the end to make sure EITR==0 case is handled
* correctly w.r.t stopping tx, and changing TXDCTL.WTHRESH settings
* also locks in RSC enable/disable which requires reset
*/
if (need_reset) {
if (netif_running(netdev))
ixgbe_reinit_locked(adapter);
else
ixgbe_reset(adapter);
}
return 0; return 0;
} }

View File

@ -2945,8 +2945,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
for (i = 0; i < adapter->num_tx_queues; i++) { for (i = 0; i < adapter->num_tx_queues; i++) {
j = adapter->tx_ring[i]->reg_idx; j = adapter->tx_ring[i]->reg_idx;
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
/* enable WTHRESH=8 descriptors, to encourage burst writeback */ if (adapter->rx_itr_setting == 0) {
txdctl |= (8 << 16); /* cannot set wthresh when itr==0 */
txdctl &= ~0x007F0000;
} else {
/* enable WTHRESH=8 descriptors, to encourage burst writeback */
txdctl |= (8 << 16);
}
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
} }