sfc: Replace stats_enabled flag with a disable count
Currently we use a spin-lock to serialise statistics fetches and also to inhibit them for short periods of time, plus a flag to enable/disable statistics fetches for longer periods of time, during online reset. This was apparently insufficient to deal with the several reasons for stats being disabled. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
af4ad9bca0
commit
1974cc205e
|
@ -685,7 +685,7 @@ static int efx_init_port(struct efx_nic *efx)
|
||||||
efx->mac_op->reconfigure(efx);
|
efx->mac_op->reconfigure(efx);
|
||||||
|
|
||||||
efx->port_initialized = true;
|
efx->port_initialized = true;
|
||||||
efx->stats_enabled = true;
|
efx_stats_enable(efx);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -734,6 +734,7 @@ static void efx_fini_port(struct efx_nic *efx)
|
||||||
if (!efx->port_initialized)
|
if (!efx->port_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
efx_stats_disable(efx);
|
||||||
efx->phy_op->fini(efx);
|
efx->phy_op->fini(efx);
|
||||||
efx->port_initialized = false;
|
efx->port_initialized = false;
|
||||||
|
|
||||||
|
@ -1360,6 +1361,20 @@ static int efx_net_stop(struct net_device *net_dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void efx_stats_disable(struct efx_nic *efx)
|
||||||
|
{
|
||||||
|
spin_lock(&efx->stats_lock);
|
||||||
|
++efx->stats_disable_count;
|
||||||
|
spin_unlock(&efx->stats_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void efx_stats_enable(struct efx_nic *efx)
|
||||||
|
{
|
||||||
|
spin_lock(&efx->stats_lock);
|
||||||
|
--efx->stats_disable_count;
|
||||||
|
spin_unlock(&efx->stats_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
|
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
|
||||||
static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
|
static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
|
||||||
{
|
{
|
||||||
|
@ -1368,12 +1383,12 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
|
||||||
struct net_device_stats *stats = &net_dev->stats;
|
struct net_device_stats *stats = &net_dev->stats;
|
||||||
|
|
||||||
/* Update stats if possible, but do not wait if another thread
|
/* Update stats if possible, but do not wait if another thread
|
||||||
* is updating them (or resetting the NIC); slightly stale
|
* is updating them or if MAC stats fetches are temporarily
|
||||||
* stats are acceptable.
|
* disabled; slightly stale stats are acceptable.
|
||||||
*/
|
*/
|
||||||
if (!spin_trylock(&efx->stats_lock))
|
if (!spin_trylock(&efx->stats_lock))
|
||||||
return stats;
|
return stats;
|
||||||
if (efx->stats_enabled) {
|
if (!efx->stats_disable_count) {
|
||||||
efx->mac_op->update_stats(efx);
|
efx->mac_op->update_stats(efx);
|
||||||
falcon_update_nic_stats(efx);
|
falcon_update_nic_stats(efx);
|
||||||
}
|
}
|
||||||
|
@ -1626,12 +1641,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
|
||||||
{
|
{
|
||||||
EFX_ASSERT_RESET_SERIALISED(efx);
|
EFX_ASSERT_RESET_SERIALISED(efx);
|
||||||
|
|
||||||
/* The net_dev->get_stats handler is quite slow, and will fail
|
efx_stats_disable(efx);
|
||||||
* if a fetch is pending over reset. Serialise against it. */
|
|
||||||
spin_lock(&efx->stats_lock);
|
|
||||||
efx->stats_enabled = false;
|
|
||||||
spin_unlock(&efx->stats_lock);
|
|
||||||
|
|
||||||
efx_stop_all(efx);
|
efx_stop_all(efx);
|
||||||
mutex_lock(&efx->mac_lock);
|
mutex_lock(&efx->mac_lock);
|
||||||
mutex_lock(&efx->spi_lock);
|
mutex_lock(&efx->spi_lock);
|
||||||
|
@ -1682,7 +1692,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
efx_start_all(efx);
|
efx_start_all(efx);
|
||||||
efx->stats_enabled = true;
|
efx_stats_enable(efx);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1888,6 +1898,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
|
||||||
efx->rx_checksum_enabled = true;
|
efx->rx_checksum_enabled = true;
|
||||||
spin_lock_init(&efx->netif_stop_lock);
|
spin_lock_init(&efx->netif_stop_lock);
|
||||||
spin_lock_init(&efx->stats_lock);
|
spin_lock_init(&efx->stats_lock);
|
||||||
|
efx->stats_disable_count = 1;
|
||||||
mutex_init(&efx->mac_lock);
|
mutex_init(&efx->mac_lock);
|
||||||
efx->mac_op = &efx_dummy_mac_operations;
|
efx->mac_op = &efx_dummy_mac_operations;
|
||||||
efx->phy_op = &efx_dummy_phy_operations;
|
efx->phy_op = &efx_dummy_phy_operations;
|
||||||
|
|
|
@ -36,6 +36,8 @@ extern void efx_process_channel_now(struct efx_channel *channel);
|
||||||
extern void efx_flush_queues(struct efx_nic *efx);
|
extern void efx_flush_queues(struct efx_nic *efx);
|
||||||
|
|
||||||
/* Ports */
|
/* Ports */
|
||||||
|
extern void efx_stats_disable(struct efx_nic *efx);
|
||||||
|
extern void efx_stats_enable(struct efx_nic *efx);
|
||||||
extern void efx_reconfigure_port(struct efx_nic *efx);
|
extern void efx_reconfigure_port(struct efx_nic *efx);
|
||||||
extern void __efx_reconfigure_port(struct efx_nic *efx);
|
extern void __efx_reconfigure_port(struct efx_nic *efx);
|
||||||
|
|
||||||
|
|
|
@ -1883,7 +1883,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
|
||||||
|
|
||||||
/* MAC stats will fail whilst the TX fifo is draining. Serialise
|
/* MAC stats will fail whilst the TX fifo is draining. Serialise
|
||||||
* the drain sequence with the statistics fetch */
|
* the drain sequence with the statistics fetch */
|
||||||
spin_lock(&efx->stats_lock);
|
efx_stats_disable(efx);
|
||||||
|
|
||||||
falcon_read(efx, ®, MAC0_CTRL_REG_KER);
|
falcon_read(efx, ®, MAC0_CTRL_REG_KER);
|
||||||
EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1);
|
EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1);
|
||||||
|
@ -1913,7 +1913,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
|
||||||
udelay(10);
|
udelay(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&efx->stats_lock);
|
efx_stats_enable(efx);
|
||||||
|
|
||||||
/* If we've reset the EM block and the link is up, then
|
/* If we've reset the EM block and the link is up, then
|
||||||
* we'll have to kick the XAUI link so the PHY can recover */
|
* we'll have to kick the XAUI link so the PHY can recover */
|
||||||
|
@ -2273,6 +2273,10 @@ int falcon_switch_mac(struct efx_nic *efx)
|
||||||
struct efx_mac_operations *old_mac_op = efx->mac_op;
|
struct efx_mac_operations *old_mac_op = efx->mac_op;
|
||||||
efx_oword_t nic_stat;
|
efx_oword_t nic_stat;
|
||||||
unsigned strap_val;
|
unsigned strap_val;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Don't try to fetch MAC stats while we're switching MACs */
|
||||||
|
efx_stats_disable(efx);
|
||||||
|
|
||||||
/* Internal loopbacks override the phy speed setting */
|
/* Internal loopbacks override the phy speed setting */
|
||||||
if (efx->loopback_mode == LOOPBACK_GMAC) {
|
if (efx->loopback_mode == LOOPBACK_GMAC) {
|
||||||
|
@ -2302,13 +2306,16 @@ int falcon_switch_mac(struct efx_nic *efx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_mac_op == efx->mac_op)
|
if (old_mac_op == efx->mac_op)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
|
EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
|
||||||
/* Not all macs support a mac-level link state */
|
/* Not all macs support a mac-level link state */
|
||||||
efx->mac_up = true;
|
efx->mac_up = true;
|
||||||
|
|
||||||
return falcon_reset_macs(efx);
|
rc = falcon_reset_macs(efx);
|
||||||
|
out:
|
||||||
|
efx_stats_enable(efx);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This call is responsible for hooking in the MAC and PHY operations */
|
/* This call is responsible for hooking in the MAC and PHY operations */
|
||||||
|
|
|
@ -754,8 +754,7 @@ union efx_multicast_hash {
|
||||||
* &struct net_device_stats.
|
* &struct net_device_stats.
|
||||||
* @stats_buffer: DMA buffer for statistics
|
* @stats_buffer: DMA buffer for statistics
|
||||||
* @stats_lock: Statistics update lock. Serialises statistics fetches
|
* @stats_lock: Statistics update lock. Serialises statistics fetches
|
||||||
* @stats_enabled: Temporarily disable statistics fetches.
|
* @stats_disable_count: Nest count for disabling statistics fetches
|
||||||
* Serialised by @stats_lock
|
|
||||||
* @mac_op: MAC interface
|
* @mac_op: MAC interface
|
||||||
* @mac_address: Permanent MAC address
|
* @mac_address: Permanent MAC address
|
||||||
* @phy_type: PHY type
|
* @phy_type: PHY type
|
||||||
|
@ -837,7 +836,7 @@ struct efx_nic {
|
||||||
struct efx_mac_stats mac_stats;
|
struct efx_mac_stats mac_stats;
|
||||||
struct efx_buffer stats_buffer;
|
struct efx_buffer stats_buffer;
|
||||||
spinlock_t stats_lock;
|
spinlock_t stats_lock;
|
||||||
bool stats_enabled;
|
unsigned int stats_disable_count;
|
||||||
|
|
||||||
struct efx_mac_operations *mac_op;
|
struct efx_mac_operations *mac_op;
|
||||||
unsigned char mac_address[ETH_ALEN];
|
unsigned char mac_address[ETH_ALEN];
|
||||||
|
|
|
@ -235,12 +235,18 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
|
||||||
} else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
|
} else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
} else {
|
} else {
|
||||||
|
/* Reset the PHY, reconfigure the MAC and enable/disable
|
||||||
|
* MAC stats accordingly. */
|
||||||
efx->phy_mode = new_mode;
|
efx->phy_mode = new_mode;
|
||||||
|
if (new_mode & PHY_MODE_SPECIAL)
|
||||||
|
efx_stats_disable(efx);
|
||||||
if (efx->board_info.type == EFX_BOARD_SFE4001)
|
if (efx->board_info.type == EFX_BOARD_SFE4001)
|
||||||
err = sfe4001_poweron(efx);
|
err = sfe4001_poweron(efx);
|
||||||
else
|
else
|
||||||
err = sfn4111t_reset(efx);
|
err = sfn4111t_reset(efx);
|
||||||
efx_reconfigure_port(efx);
|
efx_reconfigure_port(efx);
|
||||||
|
if (!(new_mode & PHY_MODE_SPECIAL))
|
||||||
|
efx_stats_enable(efx);
|
||||||
}
|
}
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
|
@ -329,6 +335,11 @@ int sfe4001_init(struct efx_nic *efx)
|
||||||
efx->board_info.monitor = sfe4001_check_hw;
|
efx->board_info.monitor = sfe4001_check_hw;
|
||||||
efx->board_info.fini = sfe4001_fini;
|
efx->board_info.fini = sfe4001_fini;
|
||||||
|
|
||||||
|
if (efx->phy_mode & PHY_MODE_SPECIAL) {
|
||||||
|
/* PHY won't generate a 156.25 MHz clock and MAC stats fetch
|
||||||
|
* will fail. */
|
||||||
|
efx_stats_disable(efx);
|
||||||
|
}
|
||||||
rc = sfe4001_poweron(efx);
|
rc = sfe4001_poweron(efx);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto fail_ioexp;
|
goto fail_ioexp;
|
||||||
|
@ -405,8 +416,10 @@ int sfn4111t_init(struct efx_nic *efx)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto fail_hwmon;
|
goto fail_hwmon;
|
||||||
|
|
||||||
if (efx->phy_mode & PHY_MODE_SPECIAL)
|
if (efx->phy_mode & PHY_MODE_SPECIAL) {
|
||||||
|
efx_stats_disable(efx);
|
||||||
sfn4111t_reset(efx);
|
sfn4111t_reset(efx);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -370,8 +370,8 @@ static int tenxpress_special_reset(struct efx_nic *efx)
|
||||||
|
|
||||||
/* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
|
/* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
|
||||||
* a special software reset can glitch the XGMAC sufficiently for stats
|
* a special software reset can glitch the XGMAC sufficiently for stats
|
||||||
* requests to fail. Since we don't often special_reset, just lock. */
|
* requests to fail. */
|
||||||
spin_lock(&efx->stats_lock);
|
efx_stats_disable(efx);
|
||||||
|
|
||||||
/* Initiate reset */
|
/* Initiate reset */
|
||||||
reg = mdio_clause45_read(efx, efx->mii.phy_id,
|
reg = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||||
|
@ -386,17 +386,17 @@ static int tenxpress_special_reset(struct efx_nic *efx)
|
||||||
rc = mdio_clause45_wait_reset_mmds(efx,
|
rc = mdio_clause45_wait_reset_mmds(efx,
|
||||||
TENXPRESS_REQUIRED_DEVS);
|
TENXPRESS_REQUIRED_DEVS);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto unlock;
|
goto out;
|
||||||
|
|
||||||
/* Try and reconfigure the device */
|
/* Try and reconfigure the device */
|
||||||
rc = tenxpress_init(efx);
|
rc = tenxpress_init(efx);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto unlock;
|
goto out;
|
||||||
|
|
||||||
/* Wait for the XGXS state machine to churn */
|
/* Wait for the XGXS state machine to churn */
|
||||||
mdelay(10);
|
mdelay(10);
|
||||||
unlock:
|
out:
|
||||||
spin_unlock(&efx->stats_lock);
|
efx_stats_enable(efx);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue