net/mlx5e: Add mlx5e HV VHCA stats agent
HV VHCA stats agent is responsible on running a preiodic rx/tx packets/bytes stats update. Currently the supported format is version MLX5_HV_VHCA_STATS_VERSION. Block ID 1 is dedicated for statistics data transfer from the VF to the PF. The reporter fetch the statistics data from all opened channels, fill it in a buffer and send it to mlx5_hv_vhca_write_agent. As the stats layer should include some metadata per block (sequence and offset), the HV VHCA layer shall modify the buffer before actually send it over block 1. Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
29ddad4316
commit
cef35af34d
@ -36,6 +36,7 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
|
||||
mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
|
||||
lib/geneve.o en/tc_tun_vxlan.o en/tc_tun_gre.o \
|
||||
en/tc_tun_geneve.o diag/en_tc_tracepoint.o
|
||||
mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
|
||||
|
||||
#
|
||||
# Core extra
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "mlx5_core.h"
|
||||
#include "en_stats.h"
|
||||
#include "en/fs.h"
|
||||
#include "lib/hv_vhca.h"
|
||||
|
||||
extern const struct net_device_ops mlx5e_netdev_ops;
|
||||
struct page_pool;
|
||||
@ -782,6 +783,15 @@ struct mlx5e_modify_sq_param {
|
||||
int rl_index;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_PCI_HYPERV_INTERFACE)
|
||||
struct mlx5e_hv_vhca_stats_agent {
|
||||
struct mlx5_hv_vhca_agent *agent;
|
||||
struct delayed_work work;
|
||||
u16 delay;
|
||||
void *buf;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mlx5e_xsk {
|
||||
/* UMEMs are stored separately from channels, because we don't want to
|
||||
* lose them when channels are recreated. The kernel also stores UMEMs,
|
||||
@ -853,6 +863,9 @@ struct mlx5e_priv {
|
||||
struct devlink_health_reporter *tx_reporter;
|
||||
struct devlink_health_reporter *rx_reporter;
|
||||
struct mlx5e_xsk xsk;
|
||||
#if IS_ENABLED(CONFIG_PCI_HYPERV_INTERFACE)
|
||||
struct mlx5e_hv_vhca_stats_agent stats_agent;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mlx5e_profile {
|
||||
|
162
drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c
Normal file
162
drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c
Normal file
@ -0,0 +1,162 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
// Copyright (c) 2018 Mellanox Technologies
|
||||
|
||||
#include "en.h"
|
||||
#include "en/hv_vhca_stats.h"
|
||||
#include "lib/hv_vhca.h"
|
||||
#include "lib/hv.h"
|
||||
|
||||
struct mlx5e_hv_vhca_per_ring_stats {
|
||||
u64 rx_packets;
|
||||
u64 rx_bytes;
|
||||
u64 tx_packets;
|
||||
u64 tx_bytes;
|
||||
};
|
||||
|
||||
static void
|
||||
mlx5e_hv_vhca_fill_ring_stats(struct mlx5e_priv *priv, int ch,
|
||||
struct mlx5e_hv_vhca_per_ring_stats *data)
|
||||
{
|
||||
struct mlx5e_channel_stats *stats;
|
||||
int tc;
|
||||
|
||||
stats = &priv->channel_stats[ch];
|
||||
data->rx_packets = stats->rq.packets;
|
||||
data->rx_bytes = stats->rq.bytes;
|
||||
|
||||
for (tc = 0; tc < priv->max_opened_tc; tc++) {
|
||||
data->tx_packets += stats->sq[tc].packets;
|
||||
data->tx_bytes += stats->sq[tc].bytes;
|
||||
}
|
||||
}
|
||||
|
||||
static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, u64 *data,
|
||||
int buf_len)
|
||||
{
|
||||
int ch, i = 0;
|
||||
|
||||
for (ch = 0; ch < priv->max_nch; ch++) {
|
||||
u64 *buf = data + i;
|
||||
|
||||
if (WARN_ON_ONCE(buf +
|
||||
sizeof(struct mlx5e_hv_vhca_per_ring_stats) >
|
||||
data + buf_len))
|
||||
return;
|
||||
|
||||
mlx5e_hv_vhca_fill_ring_stats(priv, ch,
|
||||
(struct mlx5e_hv_vhca_per_ring_stats *)buf);
|
||||
i += sizeof(struct mlx5e_hv_vhca_per_ring_stats) / sizeof(u64);
|
||||
}
|
||||
}
|
||||
|
||||
static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv)
|
||||
{
|
||||
return (sizeof(struct mlx5e_hv_vhca_per_ring_stats) *
|
||||
priv->max_nch);
|
||||
}
|
||||
|
||||
static void mlx5e_hv_vhca_stats_work(struct work_struct *work)
|
||||
{
|
||||
struct mlx5e_hv_vhca_stats_agent *sagent;
|
||||
struct mlx5_hv_vhca_agent *agent;
|
||||
struct delayed_work *dwork;
|
||||
struct mlx5e_priv *priv;
|
||||
int buf_len, rc;
|
||||
void *buf;
|
||||
|
||||
dwork = to_delayed_work(work);
|
||||
sagent = container_of(dwork, struct mlx5e_hv_vhca_stats_agent, work);
|
||||
priv = container_of(sagent, struct mlx5e_priv, stats_agent);
|
||||
buf_len = mlx5e_hv_vhca_stats_buf_size(priv);
|
||||
agent = sagent->agent;
|
||||
buf = sagent->buf;
|
||||
|
||||
memset(buf, 0, buf_len);
|
||||
mlx5e_hv_vhca_fill_stats(priv, buf, buf_len);
|
||||
|
||||
rc = mlx5_hv_vhca_agent_write(agent, buf, buf_len);
|
||||
if (rc) {
|
||||
mlx5_core_err(priv->mdev,
|
||||
"%s: Failed to write stats, err = %d\n",
|
||||
__func__, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sagent->delay)
|
||||
queue_delayed_work(priv->wq, &sagent->work, sagent->delay);
|
||||
}
|
||||
|
||||
enum {
|
||||
MLX5_HV_VHCA_STATS_VERSION = 1,
|
||||
MLX5_HV_VHCA_STATS_UPDATE_ONCE = 0xFFFF,
|
||||
};
|
||||
|
||||
static void mlx5e_hv_vhca_stats_control(struct mlx5_hv_vhca_agent *agent,
|
||||
struct mlx5_hv_vhca_control_block *block)
|
||||
{
|
||||
struct mlx5e_hv_vhca_stats_agent *sagent;
|
||||
struct mlx5e_priv *priv;
|
||||
|
||||
priv = mlx5_hv_vhca_agent_priv(agent);
|
||||
sagent = &priv->stats_agent;
|
||||
|
||||
block->version = MLX5_HV_VHCA_STATS_VERSION;
|
||||
block->rings = priv->max_nch;
|
||||
|
||||
if (!block->command) {
|
||||
cancel_delayed_work_sync(&priv->stats_agent.work);
|
||||
return;
|
||||
}
|
||||
|
||||
sagent->delay = block->command == MLX5_HV_VHCA_STATS_UPDATE_ONCE ? 0 :
|
||||
msecs_to_jiffies(block->command * 100);
|
||||
|
||||
queue_delayed_work(priv->wq, &sagent->work, sagent->delay);
|
||||
}
|
||||
|
||||
static void mlx5e_hv_vhca_stats_cleanup(struct mlx5_hv_vhca_agent *agent)
|
||||
{
|
||||
struct mlx5e_priv *priv = mlx5_hv_vhca_agent_priv(agent);
|
||||
|
||||
cancel_delayed_work_sync(&priv->stats_agent.work);
|
||||
}
|
||||
|
||||
int mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv)
|
||||
{
|
||||
int buf_len = mlx5e_hv_vhca_stats_buf_size(priv);
|
||||
struct mlx5_hv_vhca_agent *agent;
|
||||
|
||||
priv->stats_agent.buf = kvzalloc(buf_len, GFP_KERNEL);
|
||||
if (!priv->stats_agent.buf)
|
||||
return -ENOMEM;
|
||||
|
||||
agent = mlx5_hv_vhca_agent_create(priv->mdev->hv_vhca,
|
||||
MLX5_HV_VHCA_AGENT_STATS,
|
||||
mlx5e_hv_vhca_stats_control, NULL,
|
||||
mlx5e_hv_vhca_stats_cleanup,
|
||||
priv);
|
||||
|
||||
if (IS_ERR_OR_NULL(agent)) {
|
||||
if (IS_ERR(agent))
|
||||
netdev_warn(priv->netdev,
|
||||
"Failed to create hv vhca stats agent, err = %ld\n",
|
||||
PTR_ERR(agent));
|
||||
|
||||
kfree(priv->stats_agent.buf);
|
||||
return IS_ERR_OR_NULL(agent);
|
||||
}
|
||||
|
||||
priv->stats_agent.agent = agent;
|
||||
INIT_DELAYED_WORK(&priv->stats_agent.work, mlx5e_hv_vhca_stats_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(priv->stats_agent.agent))
|
||||
return;
|
||||
|
||||
mlx5_hv_vhca_agent_destroy(priv->stats_agent.agent);
|
||||
kfree(priv->stats_agent.buf);
|
||||
}
|
25
drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.h
Normal file
25
drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
|
||||
/* Copyright (c) 2019 Mellanox Technologies. */
|
||||
|
||||
#ifndef __MLX5_EN_STATS_VHCA_H__
|
||||
#define __MLX5_EN_STATS_VHCA_H__
|
||||
#include "en.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_PCI_HYPERV_INTERFACE)
|
||||
|
||||
int mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv);
|
||||
void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv);
|
||||
|
||||
#else
|
||||
|
||||
static inline int mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MLX5_EN_STATS_VHCA_H__ */
|
@ -62,6 +62,7 @@
|
||||
#include "en/xsk/setup.h"
|
||||
#include "en/xsk/rx.h"
|
||||
#include "en/xsk/tx.h"
|
||||
#include "en/hv_vhca_stats.h"
|
||||
|
||||
|
||||
bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
|
||||
@ -5109,6 +5110,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
|
||||
if (mlx5e_monitor_counter_supported(priv))
|
||||
mlx5e_monitor_counter_init(priv);
|
||||
|
||||
mlx5e_hv_vhca_stats_create(priv);
|
||||
if (netdev->reg_state != NETREG_REGISTERED)
|
||||
return;
|
||||
#ifdef CONFIG_MLX5_CORE_EN_DCB
|
||||
@ -5141,6 +5143,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
|
||||
|
||||
queue_work(priv->wq, &priv->set_rx_mode_work);
|
||||
|
||||
mlx5e_hv_vhca_stats_destroy(priv);
|
||||
if (mlx5e_monitor_counter_supported(priv))
|
||||
mlx5e_monitor_counter_cleanup(priv);
|
||||
|
||||
|
@ -13,6 +13,7 @@ struct mlx5_hv_vhca_control_block;
|
||||
|
||||
enum mlx5_hv_vhca_agent_type {
|
||||
MLX5_HV_VHCA_AGENT_CONTROL = 0,
|
||||
MLX5_HV_VHCA_AGENT_STATS = 1,
|
||||
MLX5_HV_VHCA_AGENT_MAX = 32,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user