Commit cef35af3 authored by Eran Ben Elisha's avatar Eran Ben Elisha Committed by David S. Miller
Browse files

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: default avatarEran Ben Elisha <eranbe@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 29ddad43
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+13 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
// 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 −0
Original line number Diff line number Diff line
/* 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__ */
+3 −0
Original line number Diff line number Diff line
@@ -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);

Loading