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