1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2015 6WIND S.A.
3 * Copyright 2015 Mellanox Technologies, Ltd
4 */
5
6 #include <stddef.h>
7 #include <stdint.h>
8 #include <errno.h>
9 #include <string.h>
10
11 #include <rte_malloc.h>
12 #include <ethdev_driver.h>
13
14 #include <mlx5_malloc.h>
15
16 #include "mlx5_defs.h"
17 #include "mlx5.h"
18 #include "mlx5_rxtx.h"
19 #include "mlx5_rx.h"
20
21 /**
22 * DPDK callback to update the RSS hash configuration.
23 *
24 * @param dev
25 * Pointer to Ethernet device structure.
26 * @param[in] rss_conf
27 * RSS configuration data.
28 *
29 * @return
30 * 0 on success, a negative errno value otherwise and rte_errno is set.
31 */
32 int
mlx5_rss_hash_update(struct rte_eth_dev * dev,struct rte_eth_rss_conf * rss_conf)33 mlx5_rss_hash_update(struct rte_eth_dev *dev,
34 struct rte_eth_rss_conf *rss_conf)
35 {
36 struct mlx5_priv *priv = dev->data->dev_private;
37 unsigned int i;
38 unsigned int idx;
39
40 if (rss_conf->rss_hf & MLX5_RSS_HF_MASK) {
41 rte_errno = EINVAL;
42 return -rte_errno;
43 }
44 if (rss_conf->rss_key && rss_conf->rss_key_len) {
45 if (rss_conf->rss_key_len != MLX5_RSS_HASH_KEY_LEN) {
46 DRV_LOG(ERR,
47 "port %u RSS key len must be %s Bytes long",
48 dev->data->port_id,
49 RTE_STR(MLX5_RSS_HASH_KEY_LEN));
50 rte_errno = EINVAL;
51 return -rte_errno;
52 }
53 priv->rss_conf.rss_key = mlx5_realloc(priv->rss_conf.rss_key,
54 MLX5_MEM_RTE,
55 rss_conf->rss_key_len,
56 0, SOCKET_ID_ANY);
57 if (!priv->rss_conf.rss_key) {
58 rte_errno = ENOMEM;
59 return -rte_errno;
60 }
61 memcpy(priv->rss_conf.rss_key, rss_conf->rss_key,
62 rss_conf->rss_key_len);
63 priv->rss_conf.rss_key_len = rss_conf->rss_key_len;
64 }
65 priv->rss_conf.rss_hf = rss_conf->rss_hf;
66 /* Enable the RSS hash in all Rx queues. */
67 for (i = 0, idx = 0; idx != priv->rxqs_n; ++i) {
68 struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, i);
69
70 if (rxq == NULL || rxq->ctrl == NULL)
71 continue;
72 rxq->ctrl->rxq.rss_hash = !!rss_conf->rss_hf &&
73 !!(dev->data->dev_conf.rxmode.mq_mode & RTE_ETH_MQ_RX_RSS);
74 ++idx;
75 }
76 return 0;
77 }
78
79 /**
80 * DPDK callback to get the RSS hash configuration.
81 *
82 * @param dev
83 * Pointer to Ethernet device structure.
84 * @param[in, out] rss_conf
85 * RSS configuration data.
86 *
87 * @return
88 * 0 on success, a negative errno value otherwise and rte_errno is set.
89 */
90 int
mlx5_rss_hash_conf_get(struct rte_eth_dev * dev,struct rte_eth_rss_conf * rss_conf)91 mlx5_rss_hash_conf_get(struct rte_eth_dev *dev,
92 struct rte_eth_rss_conf *rss_conf)
93 {
94 struct mlx5_priv *priv = dev->data->dev_private;
95
96 if (!rss_conf) {
97 rte_errno = EINVAL;
98 return -rte_errno;
99 }
100 if (rss_conf->rss_key &&
101 (rss_conf->rss_key_len >= priv->rss_conf.rss_key_len)) {
102 memcpy(rss_conf->rss_key, priv->rss_conf.rss_key,
103 priv->rss_conf.rss_key_len);
104 }
105 rss_conf->rss_key_len = priv->rss_conf.rss_key_len;
106 rss_conf->rss_hf = priv->rss_conf.rss_hf;
107 return 0;
108 }
109
110 /**
111 * Allocate/reallocate RETA index table.
112 *
113 * @param dev
114 * Pointer to Ethernet device.
115 * @praram reta_size
116 * The size of the array to allocate.
117 *
118 * @return
119 * 0 on success, a negative errno value otherwise and rte_errno is set.
120 */
121 int
mlx5_rss_reta_index_resize(struct rte_eth_dev * dev,unsigned int reta_size)122 mlx5_rss_reta_index_resize(struct rte_eth_dev *dev, unsigned int reta_size)
123 {
124 struct mlx5_priv *priv = dev->data->dev_private;
125 void *mem;
126 unsigned int old_size = priv->reta_idx_n;
127
128 if (priv->reta_idx_n == reta_size)
129 return 0;
130
131 mem = mlx5_realloc(priv->reta_idx, MLX5_MEM_RTE,
132 reta_size * sizeof((*priv->reta_idx)[0]), 0,
133 SOCKET_ID_ANY);
134 if (!mem) {
135 rte_errno = ENOMEM;
136 return -rte_errno;
137 }
138 priv->reta_idx = mem;
139 priv->reta_idx_n = reta_size;
140 if (old_size < reta_size)
141 memset(&(*priv->reta_idx)[old_size], 0,
142 (reta_size - old_size) *
143 sizeof((*priv->reta_idx)[0]));
144 return 0;
145 }
146
147 /**
148 * DPDK callback to get the RETA indirection table.
149 *
150 * @param dev
151 * Pointer to Ethernet device structure.
152 * @param reta_conf
153 * Pointer to RETA configuration structure array.
154 * @param reta_size
155 * Size of the RETA table.
156 *
157 * @return
158 * 0 on success, a negative errno value otherwise and rte_errno is set.
159 */
160 int
mlx5_dev_rss_reta_query(struct rte_eth_dev * dev,struct rte_eth_rss_reta_entry64 * reta_conf,uint16_t reta_size)161 mlx5_dev_rss_reta_query(struct rte_eth_dev *dev,
162 struct rte_eth_rss_reta_entry64 *reta_conf,
163 uint16_t reta_size)
164 {
165 struct mlx5_priv *priv = dev->data->dev_private;
166 unsigned int idx;
167 unsigned int i;
168
169 if (!reta_size || reta_size > priv->reta_idx_n) {
170 rte_errno = EINVAL;
171 return -rte_errno;
172 }
173 /* Fill each entry of the table even if its bit is not set. */
174 for (idx = 0, i = 0; (i != reta_size); ++i) {
175 idx = i / RTE_ETH_RETA_GROUP_SIZE;
176 reta_conf[idx].reta[i % RTE_ETH_RETA_GROUP_SIZE] =
177 (*priv->reta_idx)[i];
178 }
179 return 0;
180 }
181
182 /**
183 * DPDK callback to update the RETA indirection table.
184 *
185 * @param dev
186 * Pointer to Ethernet device structure.
187 * @param reta_conf
188 * Pointer to RETA configuration structure array.
189 * @param reta_size
190 * Size of the RETA table.
191 *
192 * @return
193 * 0 on success, a negative errno value otherwise and rte_errno is set.
194 */
195 int
mlx5_dev_rss_reta_update(struct rte_eth_dev * dev,struct rte_eth_rss_reta_entry64 * reta_conf,uint16_t reta_size)196 mlx5_dev_rss_reta_update(struct rte_eth_dev *dev,
197 struct rte_eth_rss_reta_entry64 *reta_conf,
198 uint16_t reta_size)
199 {
200 int ret;
201 struct mlx5_priv *priv = dev->data->dev_private;
202 unsigned int idx;
203 unsigned int i;
204 unsigned int pos;
205
206 if (!reta_size) {
207 rte_errno = EINVAL;
208 return -rte_errno;
209 }
210 ret = mlx5_rss_reta_index_resize(dev, reta_size);
211 if (ret)
212 return ret;
213 for (idx = 0, i = 0; (i != reta_size); ++i) {
214 idx = i / RTE_ETH_RETA_GROUP_SIZE;
215 pos = i % RTE_ETH_RETA_GROUP_SIZE;
216 if (((reta_conf[idx].mask >> pos) & 0x1) == 0)
217 continue;
218 MLX5_ASSERT(reta_conf[idx].reta[pos] < priv->rxqs_n);
219 (*priv->reta_idx)[i] = reta_conf[idx].reta[pos];
220 }
221 priv->skip_default_rss_reta = 1;
222 return mlx5_traffic_restart(dev);
223 }
224