net: sfc: Replace in_interrupt() usage
efx_ef10_try_update_nic_stats_vf() used in_interrupt() to figure out
whether it is safe to sleep (for MCDI) or not.
The only caller from which it was not is efx_net_stats(), which can be
invoked under dev_base_lock from net-sysfs::netstat_show().
So add a new update_stats_atomic() method to struct efx_nic_type, and call
it from efx_net_stats(), removing the need for
efx_ef10_try_update_nic_stats_vf() to behave differently for this case
(which it wasn't doing correctly anyway).
For all nic_types other than EF10 VF, this method is NULL so the the
regular update_stats() methods are invoked , which are happy with being
called from atomic contexts.
Fixes: f00bf2305c
("sfc: don't update stats on VF when called in atomic context")
Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Martin Habets <mhabets@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
606dbf8d5d
Коммит
623b9988bf
|
@ -1871,15 +1871,6 @@ static int efx_ef10_try_update_nic_stats_vf(struct efx_nic *efx)
|
||||||
|
|
||||||
spin_unlock_bh(&efx->stats_lock);
|
spin_unlock_bh(&efx->stats_lock);
|
||||||
|
|
||||||
if (in_interrupt()) {
|
|
||||||
/* If in atomic context, cannot update stats. Just update the
|
|
||||||
* software stats and return so the caller can continue.
|
|
||||||
*/
|
|
||||||
spin_lock_bh(&efx->stats_lock);
|
|
||||||
efx_update_sw_stats(efx, stats);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
efx_ef10_get_stat_mask(efx, mask);
|
efx_ef10_get_stat_mask(efx, mask);
|
||||||
|
|
||||||
rc = efx_nic_alloc_buffer(efx, &stats_buf, dma_len, GFP_ATOMIC);
|
rc = efx_nic_alloc_buffer(efx, &stats_buf, dma_len, GFP_ATOMIC);
|
||||||
|
@ -1938,6 +1929,18 @@ static size_t efx_ef10_update_stats_vf(struct efx_nic *efx, u64 *full_stats,
|
||||||
return efx_ef10_update_stats_common(efx, full_stats, core_stats);
|
return efx_ef10_update_stats_common(efx, full_stats, core_stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t efx_ef10_update_stats_atomic_vf(struct efx_nic *efx, u64 *full_stats,
|
||||||
|
struct rtnl_link_stats64 *core_stats)
|
||||||
|
{
|
||||||
|
struct efx_ef10_nic_data *nic_data = efx->nic_data;
|
||||||
|
|
||||||
|
/* In atomic context, cannot update HW stats. Just update the
|
||||||
|
* software stats and return so the caller can continue.
|
||||||
|
*/
|
||||||
|
efx_update_sw_stats(efx, nic_data->stats);
|
||||||
|
return efx_ef10_update_stats_common(efx, full_stats, core_stats);
|
||||||
|
}
|
||||||
|
|
||||||
static void efx_ef10_push_irq_moderation(struct efx_channel *channel)
|
static void efx_ef10_push_irq_moderation(struct efx_channel *channel)
|
||||||
{
|
{
|
||||||
struct efx_nic *efx = channel->efx;
|
struct efx_nic *efx = channel->efx;
|
||||||
|
@ -3998,6 +4001,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
|
||||||
.finish_flr = efx_port_dummy_op_void,
|
.finish_flr = efx_port_dummy_op_void,
|
||||||
.describe_stats = efx_ef10_describe_stats,
|
.describe_stats = efx_ef10_describe_stats,
|
||||||
.update_stats = efx_ef10_update_stats_vf,
|
.update_stats = efx_ef10_update_stats_vf,
|
||||||
|
.update_stats_atomic = efx_ef10_update_stats_atomic_vf,
|
||||||
.start_stats = efx_port_dummy_op_void,
|
.start_stats = efx_port_dummy_op_void,
|
||||||
.pull_stats = efx_port_dummy_op_void,
|
.pull_stats = efx_port_dummy_op_void,
|
||||||
.stop_stats = efx_port_dummy_op_void,
|
.stop_stats = efx_port_dummy_op_void,
|
||||||
|
|
|
@ -602,7 +602,7 @@ void efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats)
|
||||||
struct efx_nic *efx = netdev_priv(net_dev);
|
struct efx_nic *efx = netdev_priv(net_dev);
|
||||||
|
|
||||||
spin_lock_bh(&efx->stats_lock);
|
spin_lock_bh(&efx->stats_lock);
|
||||||
efx->type->update_stats(efx, NULL, stats);
|
efx_nic_update_stats_atomic(efx, NULL, stats);
|
||||||
spin_unlock_bh(&efx->stats_lock);
|
spin_unlock_bh(&efx->stats_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1172,6 +1172,9 @@ struct efx_udp_tunnel {
|
||||||
* @describe_stats: Describe statistics for ethtool
|
* @describe_stats: Describe statistics for ethtool
|
||||||
* @update_stats: Update statistics not provided by event handling.
|
* @update_stats: Update statistics not provided by event handling.
|
||||||
* Either argument may be %NULL.
|
* Either argument may be %NULL.
|
||||||
|
* @update_stats_atomic: Update statistics while in atomic context, if that
|
||||||
|
* is more limiting than @update_stats. Otherwise, leave %NULL and
|
||||||
|
* driver core will call @update_stats.
|
||||||
* @start_stats: Start the regular fetching of statistics
|
* @start_stats: Start the regular fetching of statistics
|
||||||
* @pull_stats: Pull stats from the NIC and wait until they arrive.
|
* @pull_stats: Pull stats from the NIC and wait until they arrive.
|
||||||
* @stop_stats: Stop the regular fetching of statistics
|
* @stop_stats: Stop the regular fetching of statistics
|
||||||
|
@ -1316,6 +1319,8 @@ struct efx_nic_type {
|
||||||
size_t (*describe_stats)(struct efx_nic *efx, u8 *names);
|
size_t (*describe_stats)(struct efx_nic *efx, u8 *names);
|
||||||
size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats,
|
size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats,
|
||||||
struct rtnl_link_stats64 *core_stats);
|
struct rtnl_link_stats64 *core_stats);
|
||||||
|
size_t (*update_stats_atomic)(struct efx_nic *efx, u64 *full_stats,
|
||||||
|
struct rtnl_link_stats64 *core_stats);
|
||||||
void (*start_stats)(struct efx_nic *efx);
|
void (*start_stats)(struct efx_nic *efx);
|
||||||
void (*pull_stats)(struct efx_nic *efx);
|
void (*pull_stats)(struct efx_nic *efx);
|
||||||
void (*stop_stats)(struct efx_nic *efx);
|
void (*stop_stats)(struct efx_nic *efx);
|
||||||
|
|
|
@ -244,6 +244,13 @@ void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
|
||||||
const unsigned long *mask, u64 *stats,
|
const unsigned long *mask, u64 *stats,
|
||||||
const void *dma_buf, bool accumulate);
|
const void *dma_buf, bool accumulate);
|
||||||
void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *stat);
|
void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *stat);
|
||||||
|
static inline size_t efx_nic_update_stats_atomic(struct efx_nic *efx, u64 *full_stats,
|
||||||
|
struct rtnl_link_stats64 *core_stats)
|
||||||
|
{
|
||||||
|
if (efx->type->update_stats_atomic)
|
||||||
|
return efx->type->update_stats_atomic(efx, full_stats, core_stats);
|
||||||
|
return efx->type->update_stats(efx, full_stats, core_stats);
|
||||||
|
}
|
||||||
|
|
||||||
#define EFX_MAX_FLUSH_TIME 5000
|
#define EFX_MAX_FLUSH_TIME 5000
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче