net/sfc: add port representors infrastructure
[dpdk.git] / drivers / net / sfc / sfc_repr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  * Copyright(c) 2019 Solarflare Communications Inc.
5  *
6  * This software was jointly developed between OKTET Labs (under contract
7  * for Solarflare) and Solarflare Communications, Inc.
8  */
9
10 #include <stdint.h>
11
12 #include <rte_ethdev.h>
13 #include <rte_malloc.h>
14 #include <ethdev_driver.h>
15
16 #include "efx.h"
17
18 #include "sfc_log.h"
19 #include "sfc_debug.h"
20 #include "sfc_repr.h"
21 #include "sfc_ethdev_state.h"
22 #include "sfc_switch.h"
23
24 /** Multi-process shared representor private data */
25 struct sfc_repr_shared {
26         uint16_t                pf_port_id;
27         uint16_t                repr_id;
28         uint16_t                switch_domain_id;
29         uint16_t                switch_port_id;
30 };
31
32 /** Primary process representor private data */
33 struct sfc_repr {
34         /**
35          * PMD setup and configuration is not thread safe. Since it is not
36          * performance sensitive, it is better to guarantee thread-safety
37          * and add device level lock. Adapter control operations which
38          * change its state should acquire the lock.
39          */
40         rte_spinlock_t                  lock;
41         enum sfc_ethdev_state           state;
42 };
43
44 #define sfcr_err(sr, ...) \
45         do {                                                            \
46                 const struct sfc_repr *_sr = (sr);                      \
47                                                                         \
48                 (void)_sr;                                              \
49                 SFC_GENERIC_LOG(ERR, __VA_ARGS__);                      \
50         } while (0)
51
52 #define sfcr_info(sr, ...) \
53         do {                                                            \
54                 const struct sfc_repr *_sr = (sr);                      \
55                                                                         \
56                 (void)_sr;                                              \
57                 SFC_GENERIC_LOG(INFO,                                   \
58                                 RTE_FMT("%s() "                         \
59                                 RTE_FMT_HEAD(__VA_ARGS__ ,),            \
60                                 __func__,                               \
61                                 RTE_FMT_TAIL(__VA_ARGS__ ,)));          \
62         } while (0)
63
64 static inline struct sfc_repr_shared *
65 sfc_repr_shared_by_eth_dev(struct rte_eth_dev *eth_dev)
66 {
67         struct sfc_repr_shared *srs = eth_dev->data->dev_private;
68
69         return srs;
70 }
71
72 static inline struct sfc_repr *
73 sfc_repr_by_eth_dev(struct rte_eth_dev *eth_dev)
74 {
75         struct sfc_repr *sr = eth_dev->process_private;
76
77         return sr;
78 }
79
80 /*
81  * Add wrapper functions to acquire/release lock to be able to remove or
82  * change the lock in one place.
83  */
84
85 static inline void
86 sfc_repr_lock_init(struct sfc_repr *sr)
87 {
88         rte_spinlock_init(&sr->lock);
89 }
90
91 #if defined(RTE_LIBRTE_SFC_EFX_DEBUG) || defined(RTE_ENABLE_ASSERT)
92
93 static inline int
94 sfc_repr_lock_is_locked(struct sfc_repr *sr)
95 {
96         return rte_spinlock_is_locked(&sr->lock);
97 }
98
99 #endif
100
101 static inline void
102 sfc_repr_lock(struct sfc_repr *sr)
103 {
104         rte_spinlock_lock(&sr->lock);
105 }
106
107 static inline void
108 sfc_repr_unlock(struct sfc_repr *sr)
109 {
110         rte_spinlock_unlock(&sr->lock);
111 }
112
113 static inline void
114 sfc_repr_lock_fini(__rte_unused struct sfc_repr *sr)
115 {
116         /* Just for symmetry of the API */
117 }
118
119 static int
120 sfc_repr_check_conf(struct sfc_repr *sr, uint16_t nb_rx_queues,
121                     const struct rte_eth_conf *conf)
122 {
123         const struct rte_eth_rss_conf *rss_conf;
124         int ret = 0;
125
126         sfcr_info(sr, "entry");
127
128         if (conf->link_speeds != 0) {
129                 sfcr_err(sr, "specific link speeds not supported");
130                 ret = -EINVAL;
131         }
132
133         switch (conf->rxmode.mq_mode) {
134         case ETH_MQ_RX_RSS:
135                 if (nb_rx_queues != 1) {
136                         sfcr_err(sr, "Rx RSS is not supported with %u queues",
137                                  nb_rx_queues);
138                         ret = -EINVAL;
139                         break;
140                 }
141
142                 rss_conf = &conf->rx_adv_conf.rss_conf;
143                 if (rss_conf->rss_key != NULL || rss_conf->rss_key_len != 0 ||
144                     rss_conf->rss_hf != 0) {
145                         sfcr_err(sr, "Rx RSS configuration is not supported");
146                         ret = -EINVAL;
147                 }
148                 break;
149         case ETH_MQ_RX_NONE:
150                 break;
151         default:
152                 sfcr_err(sr, "Rx mode MQ modes other than RSS not supported");
153                 ret = -EINVAL;
154                 break;
155         }
156
157         if (conf->txmode.mq_mode != ETH_MQ_TX_NONE) {
158                 sfcr_err(sr, "Tx mode MQ modes not supported");
159                 ret = -EINVAL;
160         }
161
162         if (conf->lpbk_mode != 0) {
163                 sfcr_err(sr, "loopback not supported");
164                 ret = -EINVAL;
165         }
166
167         if (conf->dcb_capability_en != 0) {
168                 sfcr_err(sr, "priority-based flow control not supported");
169                 ret = -EINVAL;
170         }
171
172         if (conf->fdir_conf.mode != RTE_FDIR_MODE_NONE) {
173                 sfcr_err(sr, "Flow Director not supported");
174                 ret = -EINVAL;
175         }
176
177         if (conf->intr_conf.lsc != 0) {
178                 sfcr_err(sr, "link status change interrupt not supported");
179                 ret = -EINVAL;
180         }
181
182         if (conf->intr_conf.rxq != 0) {
183                 sfcr_err(sr, "receive queue interrupt not supported");
184                 ret = -EINVAL;
185         }
186
187         if (conf->intr_conf.rmv != 0) {
188                 sfcr_err(sr, "remove interrupt not supported");
189                 ret = -EINVAL;
190         }
191
192         sfcr_info(sr, "done %d", ret);
193
194         return ret;
195 }
196
197
198 static int
199 sfc_repr_configure(struct sfc_repr *sr, uint16_t nb_rx_queues,
200                    const struct rte_eth_conf *conf)
201 {
202         int ret;
203
204         sfcr_info(sr, "entry");
205
206         SFC_ASSERT(sfc_repr_lock_is_locked(sr));
207
208         ret = sfc_repr_check_conf(sr, nb_rx_queues, conf);
209         if (ret != 0)
210                 goto fail_check_conf;
211
212         sr->state = SFC_ETHDEV_CONFIGURED;
213
214         sfcr_info(sr, "done");
215
216         return 0;
217
218 fail_check_conf:
219         sfcr_info(sr, "failed %s", rte_strerror(-ret));
220         return ret;
221 }
222
223 static int
224 sfc_repr_dev_configure(struct rte_eth_dev *dev)
225 {
226         struct sfc_repr *sr = sfc_repr_by_eth_dev(dev);
227         struct rte_eth_dev_data *dev_data = dev->data;
228         int ret;
229
230         sfcr_info(sr, "entry n_rxq=%u n_txq=%u",
231                   dev_data->nb_rx_queues, dev_data->nb_tx_queues);
232
233         sfc_repr_lock(sr);
234         switch (sr->state) {
235         case SFC_ETHDEV_CONFIGURED:
236                 /* FALLTHROUGH */
237         case SFC_ETHDEV_INITIALIZED:
238                 ret = sfc_repr_configure(sr, dev_data->nb_rx_queues,
239                                          &dev_data->dev_conf);
240                 break;
241         default:
242                 sfcr_err(sr, "unexpected adapter state %u to configure",
243                          sr->state);
244                 ret = -EINVAL;
245                 break;
246         }
247         sfc_repr_unlock(sr);
248
249         sfcr_info(sr, "done %s", rte_strerror(-ret));
250
251         return ret;
252 }
253
254 static int
255 sfc_repr_dev_infos_get(struct rte_eth_dev *dev,
256                        struct rte_eth_dev_info *dev_info)
257 {
258         struct sfc_repr_shared *srs = sfc_repr_shared_by_eth_dev(dev);
259
260         dev_info->device = dev->device;
261
262         dev_info->max_rx_queues = SFC_REPR_RXQ_MAX;
263         dev_info->max_tx_queues = SFC_REPR_TXQ_MAX;
264         dev_info->default_rxconf.rx_drop_en = 1;
265         dev_info->switch_info.domain_id = srs->switch_domain_id;
266         dev_info->switch_info.port_id = srs->switch_port_id;
267
268         return 0;
269 }
270
271 static void
272 sfc_repr_close(struct sfc_repr *sr)
273 {
274         SFC_ASSERT(sfc_repr_lock_is_locked(sr));
275
276         SFC_ASSERT(sr->state == SFC_ETHDEV_CONFIGURED);
277         sr->state = SFC_ETHDEV_CLOSING;
278
279         /* Put representor close actions here */
280
281         sr->state = SFC_ETHDEV_INITIALIZED;
282 }
283
284 static int
285 sfc_repr_dev_close(struct rte_eth_dev *dev)
286 {
287         struct sfc_repr *sr = sfc_repr_by_eth_dev(dev);
288
289         sfcr_info(sr, "entry");
290
291         sfc_repr_lock(sr);
292         switch (sr->state) {
293         case SFC_ETHDEV_CONFIGURED:
294                 sfc_repr_close(sr);
295                 SFC_ASSERT(sr->state == SFC_ETHDEV_INITIALIZED);
296                 /* FALLTHROUGH */
297         case SFC_ETHDEV_INITIALIZED:
298                 break;
299         default:
300                 sfcr_err(sr, "unexpected adapter state %u on close", sr->state);
301                 break;
302         }
303
304         /*
305          * Cleanup all resources.
306          * Rollback primary process sfc_repr_eth_dev_init() below.
307          */
308
309         dev->dev_ops = NULL;
310
311         sfc_repr_unlock(sr);
312         sfc_repr_lock_fini(sr);
313
314         sfcr_info(sr, "done");
315
316         free(sr);
317
318         return 0;
319 }
320
321 static const struct eth_dev_ops sfc_repr_dev_ops = {
322         .dev_configure                  = sfc_repr_dev_configure,
323         .dev_close                      = sfc_repr_dev_close,
324         .dev_infos_get                  = sfc_repr_dev_infos_get,
325 };
326
327
328 struct sfc_repr_init_data {
329         uint16_t                pf_port_id;
330         uint16_t                repr_id;
331         uint16_t                switch_domain_id;
332         efx_mport_sel_t         mport_sel;
333 };
334
335 static int
336 sfc_repr_assign_mae_switch_port(uint16_t switch_domain_id,
337                                 const struct sfc_mae_switch_port_request *req,
338                                 uint16_t *switch_port_id)
339 {
340         int rc;
341
342         rc = sfc_mae_assign_switch_port(switch_domain_id, req, switch_port_id);
343
344         SFC_ASSERT(rc >= 0);
345         return -rc;
346 }
347
348 static int
349 sfc_repr_eth_dev_init(struct rte_eth_dev *dev, void *init_params)
350 {
351         const struct sfc_repr_init_data *repr_data = init_params;
352         struct sfc_repr_shared *srs = sfc_repr_shared_by_eth_dev(dev);
353         struct sfc_mae_switch_port_request switch_port_request;
354         efx_mport_sel_t ethdev_mport_sel;
355         struct sfc_repr *sr;
356         int ret;
357
358         /*
359          * Currently there is no mport we can use for representor's
360          * ethdev. Use an invalid one for now. This way representors
361          * can be instantiated.
362          */
363         efx_mae_mport_invalid(&ethdev_mport_sel);
364
365         memset(&switch_port_request, 0, sizeof(switch_port_request));
366         switch_port_request.type = SFC_MAE_SWITCH_PORT_REPRESENTOR;
367         switch_port_request.ethdev_mportp = &ethdev_mport_sel;
368         switch_port_request.entity_mportp = &repr_data->mport_sel;
369         switch_port_request.ethdev_port_id = dev->data->port_id;
370
371         ret = sfc_repr_assign_mae_switch_port(repr_data->switch_domain_id,
372                                               &switch_port_request,
373                                               &srs->switch_port_id);
374         if (ret != 0) {
375                 SFC_GENERIC_LOG(ERR,
376                         "%s() failed to assign MAE switch port (domain id %u)",
377                         __func__, repr_data->switch_domain_id);
378                 goto fail_mae_assign_switch_port;
379         }
380
381         /*
382          * Allocate process private data from heap, since it should not
383          * be located in shared memory allocated using rte_malloc() API.
384          */
385         sr = calloc(1, sizeof(*sr));
386         if (sr == NULL) {
387                 ret = -ENOMEM;
388                 goto fail_alloc_sr;
389         }
390
391         sfc_repr_lock_init(sr);
392         sfc_repr_lock(sr);
393
394         dev->process_private = sr;
395
396         srs->pf_port_id = repr_data->pf_port_id;
397         srs->repr_id = repr_data->repr_id;
398         srs->switch_domain_id = repr_data->switch_domain_id;
399
400         dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;
401         dev->data->representor_id = srs->repr_id;
402         dev->data->backer_port_id = srs->pf_port_id;
403
404         dev->data->mac_addrs = rte_zmalloc("sfcr", RTE_ETHER_ADDR_LEN, 0);
405         if (dev->data->mac_addrs == NULL) {
406                 ret = -ENOMEM;
407                 goto fail_mac_addrs;
408         }
409
410         dev->dev_ops = &sfc_repr_dev_ops;
411
412         sr->state = SFC_ETHDEV_INITIALIZED;
413         sfc_repr_unlock(sr);
414
415         return 0;
416
417 fail_mac_addrs:
418         sfc_repr_unlock(sr);
419         free(sr);
420
421 fail_alloc_sr:
422 fail_mae_assign_switch_port:
423         SFC_GENERIC_LOG(ERR, "%s() failed: %s", __func__, rte_strerror(-ret));
424         return ret;
425 }
426
427 int
428 sfc_repr_create(struct rte_eth_dev *parent, uint16_t representor_id,
429                 uint16_t switch_domain_id, const efx_mport_sel_t *mport_sel)
430 {
431         struct sfc_repr_init_data repr_data;
432         char name[RTE_ETH_NAME_MAX_LEN];
433         int ret;
434
435         if (snprintf(name, sizeof(name), "net_%s_representor_%u",
436                      parent->device->name, representor_id) >=
437                         (int)sizeof(name)) {
438                 SFC_GENERIC_LOG(ERR, "%s() failed name too long", __func__);
439                 return -ENAMETOOLONG;
440         }
441
442         memset(&repr_data, 0, sizeof(repr_data));
443         repr_data.pf_port_id = parent->data->port_id;
444         repr_data.repr_id = representor_id;
445         repr_data.switch_domain_id = switch_domain_id;
446         repr_data.mport_sel = *mport_sel;
447
448         ret = rte_eth_dev_create(parent->device, name,
449                                   sizeof(struct sfc_repr_shared),
450                                   NULL, NULL,
451                                   sfc_repr_eth_dev_init, &repr_data);
452         if (ret != 0)
453                 SFC_GENERIC_LOG(ERR, "%s() failed to create device", __func__);
454
455         SFC_GENERIC_LOG(INFO, "%s() done: %s", __func__, rte_strerror(-ret));
456
457         return ret;
458 }