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 9 struct mlx5e_hv_vhca_per_ring_stats { 10 u64 rx_packets; 11 u64 rx_bytes; 12 u64 tx_packets; 13 u64 tx_bytes; 14 }; 15 16 static void 17 mlx5e_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 33 static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, u64 *data, 34 int buf_len) 35 { 36 int ch, i = 0; 37 38 for (ch = 0; ch < priv->max_nch; ch++) { 39 u64 *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, 47 (struct mlx5e_hv_vhca_per_ring_stats *)buf); 48 i += sizeof(struct mlx5e_hv_vhca_per_ring_stats) / sizeof(u64); 49 } 50 } 51 52 static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv) 53 { 54 return (sizeof(struct mlx5e_hv_vhca_per_ring_stats) * 55 priv->max_nch); 56 } 57 58 static void mlx5e_hv_vhca_stats_work(struct work_struct *work) 59 { 60 struct mlx5e_hv_vhca_stats_agent *sagent; 61 struct mlx5_hv_vhca_agent *agent; 62 struct delayed_work *dwork; 63 struct mlx5e_priv *priv; 64 int buf_len, rc; 65 void *buf; 66 67 dwork = to_delayed_work(work); 68 sagent = container_of(dwork, struct mlx5e_hv_vhca_stats_agent, work); 69 priv = container_of(sagent, struct mlx5e_priv, stats_agent); 70 buf_len = mlx5e_hv_vhca_stats_buf_size(priv); 71 agent = sagent->agent; 72 buf = sagent->buf; 73 74 memset(buf, 0, buf_len); 75 mlx5e_hv_vhca_fill_stats(priv, buf, buf_len); 76 77 rc = mlx5_hv_vhca_agent_write(agent, buf, buf_len); 78 if (rc) { 79 mlx5_core_err(priv->mdev, 80 "%s: Failed to write stats, err = %d\n", 81 __func__, rc); 82 return; 83 } 84 85 if (sagent->delay) 86 queue_delayed_work(priv->wq, &sagent->work, sagent->delay); 87 } 88 89 enum { 90 MLX5_HV_VHCA_STATS_VERSION = 1, 91 MLX5_HV_VHCA_STATS_UPDATE_ONCE = 0xFFFF, 92 }; 93 94 static void mlx5e_hv_vhca_stats_control(struct mlx5_hv_vhca_agent *agent, 95 struct mlx5_hv_vhca_control_block *block) 96 { 97 struct mlx5e_hv_vhca_stats_agent *sagent; 98 struct mlx5e_priv *priv; 99 100 priv = mlx5_hv_vhca_agent_priv(agent); 101 sagent = &priv->stats_agent; 102 103 block->version = MLX5_HV_VHCA_STATS_VERSION; 104 block->rings = priv->max_nch; 105 106 if (!block->command) { 107 cancel_delayed_work_sync(&priv->stats_agent.work); 108 return; 109 } 110 111 sagent->delay = block->command == MLX5_HV_VHCA_STATS_UPDATE_ONCE ? 0 : 112 msecs_to_jiffies(block->command * 100); 113 114 queue_delayed_work(priv->wq, &sagent->work, sagent->delay); 115 } 116 117 static void mlx5e_hv_vhca_stats_cleanup(struct mlx5_hv_vhca_agent *agent) 118 { 119 struct mlx5e_priv *priv = mlx5_hv_vhca_agent_priv(agent); 120 121 cancel_delayed_work_sync(&priv->stats_agent.work); 122 } 123 124 int mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv) 125 { 126 int buf_len = mlx5e_hv_vhca_stats_buf_size(priv); 127 struct mlx5_hv_vhca_agent *agent; 128 129 priv->stats_agent.buf = kvzalloc(buf_len, GFP_KERNEL); 130 if (!priv->stats_agent.buf) 131 return -ENOMEM; 132 133 agent = mlx5_hv_vhca_agent_create(priv->mdev->hv_vhca, 134 MLX5_HV_VHCA_AGENT_STATS, 135 mlx5e_hv_vhca_stats_control, NULL, 136 mlx5e_hv_vhca_stats_cleanup, 137 priv); 138 139 if (IS_ERR_OR_NULL(agent)) { 140 if (IS_ERR(agent)) 141 netdev_warn(priv->netdev, 142 "Failed to create hv vhca stats agent, err = %ld\n", 143 PTR_ERR(agent)); 144 145 kfree(priv->stats_agent.buf); 146 return IS_ERR_OR_NULL(agent); 147 } 148 149 priv->stats_agent.agent = agent; 150 INIT_DELAYED_WORK(&priv->stats_agent.work, mlx5e_hv_vhca_stats_work); 151 152 return 0; 153 } 154 155 void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv) 156 { 157 if (IS_ERR_OR_NULL(priv->stats_agent.agent)) 158 return; 159 160 mlx5_hv_vhca_agent_destroy(priv->stats_agent.agent); 161 kfree(priv->stats_agent.buf); 162 } 163