File Index
Files and directories
Sign in
FILE

hv_vhca_stats.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2// Copyright (c) 2018 Mellanox Technologies
  3
  4#include "en.h"
  5#include "en/hv_vhca_stats.h"
  6#include "lib/hv_vhca.h"
  7#include "lib/hv.h"
  8
  9struct mlx5e_hv_vhca_per_ring_stats {
 10	u64     rx_packets;
 11	u64     rx_bytes;
 12	u64     tx_packets;
 13	u64     tx_bytes;
 14};
 15
 16static void
 17mlx5e_hv_vhca_fill_ring_stats(struct mlx5e_priv *priv, int ch,
 18			      struct mlx5e_hv_vhca_per_ring_stats *data)
 19{
 20	struct mlx5e_channel_stats *stats;
 21	int tc;
 22
 23	stats = priv->channel_stats[ch];
 24	data->rx_packets = stats->rq.packets;
 25	data->rx_bytes   = stats->rq.bytes;
 26
 27	for (tc = 0; tc < priv->max_opened_tc; tc++) {
 28		data->tx_packets += stats->sq[tc].packets;
 29		data->tx_bytes   += stats->sq[tc].bytes;
 30	}
 31}
 32
 33static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, void *data,
 34				     int buf_len)
 35{
 36	int ch, i = 0;
 37
 38	for (ch = 0; ch < priv->stats_nch; ch++) {
 39		void *buf = data + i;
 40
 41		if (WARN_ON_ONCE(buf +
 42				 sizeof(struct mlx5e_hv_vhca_per_ring_stats) >
 43				 data + buf_len))
 44			return;
 45
 46		mlx5e_hv_vhca_fill_ring_stats(priv, ch, buf);
 47		i += sizeof(struct mlx5e_hv_vhca_per_ring_stats);
 48	}
 49}
 50
 51static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv)
 52{
 53	return (sizeof(struct mlx5e_hv_vhca_per_ring_stats) *
 54		priv->stats_nch);
 55}
 56
 57static void mlx5e_hv_vhca_stats_work(struct work_struct *work)
 58{
 59	struct mlx5e_hv_vhca_stats_agent *sagent;
 60	struct mlx5_hv_vhca_agent *agent;
 61	struct delayed_work *dwork;
 62	struct mlx5e_priv *priv;
 63	int buf_len, rc;
 64	void *buf;
 65
 66	dwork = to_delayed_work(work);
 67	sagent = container_of(dwork, struct mlx5e_hv_vhca_stats_agent, work);
 68	priv = container_of(sagent, struct mlx5e_priv, stats_agent);
 69	buf_len = mlx5e_hv_vhca_stats_buf_size(priv);
 70	agent = sagent->agent;
 71	buf = sagent->buf;
 72
 73	memset(buf, 0, buf_len);
 74	mlx5e_hv_vhca_fill_stats(priv, buf, buf_len);
 75
 76	rc = mlx5_hv_vhca_agent_write(agent, buf, buf_len);
 77	if (rc) {
 78		mlx5_core_err(priv->mdev,
 79			      "%s: Failed to write stats, err = %d\n",
 80			      __func__, rc);
 81		return;
 82	}
 83
 84	if (sagent->delay)
 85		queue_delayed_work(priv->wq, &sagent->work, sagent->delay);
 86}
 87
 88enum {
 89	MLX5_HV_VHCA_STATS_VERSION     = 1,
 90	MLX5_HV_VHCA_STATS_UPDATE_ONCE = 0xFFFF,
 91};
 92
 93static void mlx5e_hv_vhca_stats_control(struct mlx5_hv_vhca_agent *agent,
 94					struct mlx5_hv_vhca_control_block *block)
 95{
 96	struct mlx5e_hv_vhca_stats_agent *sagent;
 97	struct mlx5e_priv *priv;
 98
 99	priv = mlx5_hv_vhca_agent_priv(agent);
100	sagent = &priv->stats_agent;
101
102	block->version = MLX5_HV_VHCA_STATS_VERSION;
103	block->rings   = priv->stats_nch;
104
105	if (!block->command) {
106		cancel_delayed_work_sync(&priv->stats_agent.work);
107		return;
108	}
109
110	sagent->delay = block->command == MLX5_HV_VHCA_STATS_UPDATE_ONCE ? 0 :
111			msecs_to_jiffies(block->command * 100);
112
113	queue_delayed_work(priv->wq, &sagent->work, sagent->delay);
114}
115
116static void mlx5e_hv_vhca_stats_cleanup(struct mlx5_hv_vhca_agent *agent)
117{
118	struct mlx5e_priv *priv = mlx5_hv_vhca_agent_priv(agent);
119
120	cancel_delayed_work_sync(&priv->stats_agent.work);
121}
122
123void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv)
124{
125	int buf_len = mlx5e_hv_vhca_stats_buf_size(priv);
126	struct mlx5_hv_vhca_agent *agent;
127
128	priv->stats_agent.buf = kvzalloc(buf_len, GFP_KERNEL);
129	if (!priv->stats_agent.buf)
130		return;
131
132	agent = mlx5_hv_vhca_agent_create(priv->mdev->hv_vhca,
133					  MLX5_HV_VHCA_AGENT_STATS,
134					  mlx5e_hv_vhca_stats_control, NULL,
135					  mlx5e_hv_vhca_stats_cleanup,
136					  priv);
137
138	if (IS_ERR_OR_NULL(agent)) {
139		if (IS_ERR(agent))
140			netdev_warn(priv->netdev,
141				    "Failed to create hv vhca stats agent, err = %pe\n",
142				    agent);
143
144		kvfree(priv->stats_agent.buf);
145		return;
146	}
147
148	priv->stats_agent.agent = agent;
149	INIT_DELAYED_WORK(&priv->stats_agent.work, mlx5e_hv_vhca_stats_work);
150}
151
152void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv)
153{
154	if (IS_ERR_OR_NULL(priv->stats_agent.agent))
155		return;
156
157	mlx5_hv_vhca_agent_destroy(priv->stats_agent.agent);
158	kvfree(priv->stats_agent.buf);
159}
~/ Read-only file preview.