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