5c10e8fc7423feeff5f4cab1597b2cfec4abafe9
[dpdk.git] / drivers / net / sfc / sfc_switch.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 <stdbool.h>
11
12 #include <rte_common.h>
13 #include <rte_spinlock.h>
14
15 #include "efx.h"
16
17 #include "sfc.h"
18 #include "sfc_log.h"
19 #include "sfc_switch.h"
20
21 /**
22  * Switch port registry entry.
23  *
24  * Drivers aware of RTE switch domains also have to maintain RTE switch
25  * port IDs for RTE ethdev instances they operate. These IDs are supposed
26  * to stand for physical interconnect entities, in example, PCIe functions.
27  *
28  * In terms of MAE, a physical interconnect entity can be referred to using
29  * an MPORT selector, that is, a 32-bit value. RTE switch port IDs, in turn,
30  * are 16-bit values, so indirect mapping has to be maintained:
31  *
32  * +--------------------+          +---------------------------------------+
33  * | RTE switch port ID |  ------  |         MAE switch port entry         |
34  * +--------------------+          |         ---------------------         |
35  *                                 |                                       |
36  *                                 | Entity (PCIe function) MPORT selector |
37  *                                 |                   +                   |
38  *                                 |  Port type (independent/representor)  |
39  *                                 +---------------------------------------+
40  *
41  * This mapping comprises a port type to ensure that RTE switch port ID
42  * of a represented entity and that of its representor are different in
43  * the case when the entity gets plugged into DPDK and not into a guest.
44  *
45  * Entry data also comprises RTE ethdev's own MPORT. This value
46  * coincides with the entity MPORT in the case of independent ports.
47  * In the case of representors, this ID is not a selector and refers
48  * to an allocatable object (that is, it's likely to change on RTE
49  * ethdev replug). Flow API backend must use this value rather
50  * than entity_mport to support flow rule action PORT_ID.
51  */
52 struct sfc_mae_switch_port {
53         TAILQ_ENTRY(sfc_mae_switch_port)        switch_domain_ports;
54
55         /** RTE ethdev MPORT */
56         efx_mport_sel_t                         ethdev_mport;
57         /** RTE ethdev port ID */
58         uint16_t                                ethdev_port_id;
59
60         /** Entity (PCIe function) MPORT selector */
61         efx_mport_sel_t                         entity_mport;
62         /** Port type (independent/representor) */
63         enum sfc_mae_switch_port_type           type;
64         /** RTE switch port ID */
65         uint16_t                                id;
66
67         union sfc_mae_switch_port_data          data;
68 };
69
70 TAILQ_HEAD(sfc_mae_switch_ports, sfc_mae_switch_port);
71
72 /**
73  * Switch domain registry entry.
74  *
75  * Even if an RTE ethdev instance gets unplugged, the corresponding
76  * entry in the switch port registry will not be removed because the
77  * entity (PCIe function) MPORT is static and cannot change. If this
78  * RTE ethdev gets plugged back, the entry will be reused, and
79  * RTE switch port ID will be the same.
80  */
81 struct sfc_mae_switch_domain {
82         TAILQ_ENTRY(sfc_mae_switch_domain)      entries;
83
84         /** HW switch ID */
85         struct sfc_hw_switch_id                 *hw_switch_id;
86         /** The number of ports in the switch port registry */
87         unsigned int                            nb_ports;
88         /** Switch port registry */
89         struct sfc_mae_switch_ports             ports;
90         /** RTE switch domain ID allocated for a group of devices */
91         uint16_t                                id;
92         /** DPDK controller -> EFX interface mapping */
93         efx_pcie_interface_t                    *controllers;
94         /** Number of DPDK controllers and EFX interfaces */
95         size_t                                  nb_controllers;
96         /** MAE admin port */
97         struct sfc_mae_switch_port              *mae_admin_port;
98 };
99
100 TAILQ_HEAD(sfc_mae_switch_domains, sfc_mae_switch_domain);
101
102 /**
103  * MAE representation of RTE switch infrastructure.
104  *
105  * It is possible that an RTE flow API client tries to insert a rule
106  * referencing an RTE ethdev deployed on top of a different physical
107  * device (it may belong to the same vendor or not). This particular
108  * driver/engine cannot support this and has to turn down such rules.
109  *
110  * Technically, it's HW switch identifier which, if queried for each
111  * RTE ethdev instance, indicates relationship between the instances.
112  * In the meantime, RTE flow API clients also need to somehow figure
113  * out relationship between RTE ethdev instances in advance.
114  *
115  * The concept of RTE switch domains resolves this issue. The driver
116  * maintains a static list of switch domains which is easy to browse,
117  * and each RTE ethdev fills RTE switch parameters in device
118  * information structure which is made available to clients.
119  *
120  * Even if all RTE ethdev instances belonging to a switch domain get
121  * unplugged, the corresponding entry in the switch domain registry
122  * will not be removed because the corresponding HW switch exists
123  * regardless of its ports being plugged to DPDK or kept aside.
124  * If a port gets plugged back to DPDK, the corresponding
125  * RTE ethdev will indicate the same RTE switch domain ID.
126  */
127 struct sfc_mae_switch {
128         /** A lock to protect the whole structure */
129         rte_spinlock_t                  lock;
130         /** Switch domain registry */
131         struct sfc_mae_switch_domains   domains;
132 };
133
134 static struct sfc_mae_switch sfc_mae_switch = {
135         .lock = RTE_SPINLOCK_INITIALIZER,
136         .domains = TAILQ_HEAD_INITIALIZER(sfc_mae_switch.domains),
137 };
138
139
140 /* This function expects to be called only when the lock is held */
141 static struct sfc_mae_switch_domain *
142 sfc_mae_find_switch_domain_by_id(uint16_t switch_domain_id)
143 {
144         struct sfc_mae_switch_domain *domain;
145
146         SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
147
148         TAILQ_FOREACH(domain, &sfc_mae_switch.domains, entries) {
149                 if (domain->id == switch_domain_id)
150                         return domain;
151         }
152
153         return NULL;
154 }
155
156 int
157 sfc_mae_switch_ports_iterate(uint16_t switch_domain_id,
158                              sfc_mae_switch_port_iterator_cb *cb,
159                              void *data)
160 {
161         struct sfc_mae_switch_domain *domain;
162         struct sfc_mae_switch_port *port;
163
164         if (cb == NULL)
165                 return EINVAL;
166
167         rte_spinlock_lock(&sfc_mae_switch.lock);
168
169         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
170         if (domain == NULL) {
171                 rte_spinlock_unlock(&sfc_mae_switch.lock);
172                 return EINVAL;
173         }
174
175         TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
176                 cb(port->type, &port->ethdev_mport, port->ethdev_port_id,
177                    &port->entity_mport, port->id, &port->data, data);
178         }
179
180         rte_spinlock_unlock(&sfc_mae_switch.lock);
181         return 0;
182 }
183
184 /* This function expects to be called only when the lock is held */
185 static struct sfc_mae_switch_domain *
186 sfc_mae_find_switch_domain_by_hw_switch_id(const struct sfc_hw_switch_id *id)
187 {
188         struct sfc_mae_switch_domain *domain;
189
190         SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
191
192         TAILQ_FOREACH(domain, &sfc_mae_switch.domains, entries) {
193                 if (sfc_hw_switch_ids_equal(domain->hw_switch_id, id))
194                         return domain;
195         }
196
197         return NULL;
198 }
199
200 int
201 sfc_mae_assign_switch_domain(struct sfc_adapter *sa,
202                              uint16_t *switch_domain_id)
203 {
204         struct sfc_hw_switch_id *hw_switch_id;
205         struct sfc_mae_switch_domain *domain;
206         int rc;
207
208         rte_spinlock_lock(&sfc_mae_switch.lock);
209
210         rc = sfc_hw_switch_id_init(sa, &hw_switch_id);
211         if (rc != 0)
212                 goto fail_hw_switch_id_init;
213
214         domain = sfc_mae_find_switch_domain_by_hw_switch_id(hw_switch_id);
215         if (domain != NULL) {
216                 sfc_hw_switch_id_fini(sa, hw_switch_id);
217                 goto done;
218         }
219
220         domain = rte_zmalloc("sfc_mae_switch_domain", sizeof(*domain), 0);
221         if (domain == NULL) {
222                 rc = ENOMEM;
223                 goto fail_mem_alloc;
224         }
225
226         /*
227          * This code belongs to driver init path, that is, negation is
228          * done at the end of the path by sfc_eth_dev_init(). RTE APIs
229          * negate error codes, so drop negation here.
230          */
231         rc = -rte_eth_switch_domain_alloc(&domain->id);
232         if (rc != 0)
233                 goto fail_domain_alloc;
234
235         domain->hw_switch_id = hw_switch_id;
236
237         TAILQ_INIT(&domain->ports);
238
239         TAILQ_INSERT_TAIL(&sfc_mae_switch.domains, domain, entries);
240
241 done:
242         *switch_domain_id = domain->id;
243
244         rte_spinlock_unlock(&sfc_mae_switch.lock);
245
246         return 0;
247
248 fail_domain_alloc:
249         rte_free(domain);
250
251 fail_mem_alloc:
252         sfc_hw_switch_id_fini(sa, hw_switch_id);
253
254 fail_hw_switch_id_init:
255         rte_spinlock_unlock(&sfc_mae_switch.lock);
256         return rc;
257 }
258
259 int
260 sfc_mae_switch_domain_controllers(uint16_t switch_domain_id,
261                                   const efx_pcie_interface_t **controllers,
262                                   size_t *nb_controllers)
263 {
264         struct sfc_mae_switch_domain *domain;
265
266         if (controllers == NULL || nb_controllers == NULL)
267                 return EINVAL;
268
269         rte_spinlock_lock(&sfc_mae_switch.lock);
270
271         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
272         if (domain == NULL) {
273                 rte_spinlock_unlock(&sfc_mae_switch.lock);
274                 return EINVAL;
275         }
276
277         *controllers = domain->controllers;
278         *nb_controllers = domain->nb_controllers;
279
280         rte_spinlock_unlock(&sfc_mae_switch.lock);
281         return 0;
282 }
283
284 int
285 sfc_mae_switch_domain_map_controllers(uint16_t switch_domain_id,
286                                       efx_pcie_interface_t *controllers,
287                                       size_t nb_controllers)
288 {
289         struct sfc_mae_switch_domain *domain;
290
291         rte_spinlock_lock(&sfc_mae_switch.lock);
292
293         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
294         if (domain == NULL) {
295                 rte_spinlock_unlock(&sfc_mae_switch.lock);
296                 return EINVAL;
297         }
298
299         /* Controller mapping may be set only once */
300         if (domain->controllers != NULL) {
301                 rte_spinlock_unlock(&sfc_mae_switch.lock);
302                 return EINVAL;
303         }
304
305         domain->controllers = controllers;
306         domain->nb_controllers = nb_controllers;
307
308         rte_spinlock_unlock(&sfc_mae_switch.lock);
309         return 0;
310 }
311
312 int
313 sfc_mae_switch_controller_from_mapping(const efx_pcie_interface_t *controllers,
314                                        size_t nb_controllers,
315                                        efx_pcie_interface_t intf,
316                                        int *controller)
317 {
318         size_t i;
319
320         if (controllers == NULL)
321                 return ENOENT;
322
323         for (i = 0; i < nb_controllers; i++) {
324                 if (controllers[i] == intf) {
325                         *controller = i;
326                         return 0;
327                 }
328         }
329
330         return ENOENT;
331 }
332
333 int
334 sfc_mae_switch_domain_get_controller(uint16_t switch_domain_id,
335                                      efx_pcie_interface_t intf,
336                                      int *controller)
337 {
338         const efx_pcie_interface_t *controllers;
339         size_t nb_controllers;
340         int rc;
341
342         rc = sfc_mae_switch_domain_controllers(switch_domain_id, &controllers,
343                                                &nb_controllers);
344         if (rc != 0)
345                 return rc;
346
347         return sfc_mae_switch_controller_from_mapping(controllers,
348                                                       nb_controllers,
349                                                       intf,
350                                                       controller);
351 }
352
353 int sfc_mae_switch_domain_get_intf(uint16_t switch_domain_id,
354                                    int controller,
355                                    efx_pcie_interface_t *intf)
356 {
357         const efx_pcie_interface_t *controllers;
358         size_t nb_controllers;
359         int rc;
360
361         rc = sfc_mae_switch_domain_controllers(switch_domain_id, &controllers,
362                                                &nb_controllers);
363         if (rc != 0)
364                 return rc;
365
366         if (controllers == NULL)
367                 return ENOENT;
368
369         if ((size_t)controller > nb_controllers)
370                 return EINVAL;
371
372         *intf = controllers[controller];
373
374         return 0;
375 }
376
377 /* This function expects to be called only when the lock is held */
378 static struct sfc_mae_switch_port *
379 sfc_mae_find_switch_port_by_entity(const struct sfc_mae_switch_domain *domain,
380                                    const efx_mport_sel_t *entity_mportp,
381                                    enum sfc_mae_switch_port_type type)
382 {
383         struct sfc_mae_switch_port *port;
384
385         SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
386
387         TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
388                 if (port->entity_mport.sel == entity_mportp->sel &&
389                     port->type == type)
390                         return port;
391         }
392
393         return NULL;
394 }
395
396 /* This function expects to be called only when the lock is held */
397 static int
398 sfc_mae_find_switch_port_id_by_entity(uint16_t switch_domain_id,
399                                       const efx_mport_sel_t *entity_mportp,
400                                       enum sfc_mae_switch_port_type type,
401                                       uint16_t *switch_port_id)
402 {
403         struct sfc_mae_switch_domain *domain;
404         struct sfc_mae_switch_port *port;
405
406         SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
407
408         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
409         if (domain == NULL)
410                 return EINVAL;
411
412         port = sfc_mae_find_switch_port_by_entity(domain, entity_mportp, type);
413         if (port == NULL)
414                 return ENOENT;
415
416         *switch_port_id = port->id;
417         return 0;
418 }
419
420 int
421 sfc_mae_assign_switch_port(uint16_t switch_domain_id,
422                            const struct sfc_mae_switch_port_request *req,
423                            uint16_t *switch_port_id)
424 {
425         struct sfc_mae_switch_domain *domain;
426         struct sfc_mae_switch_port *port;
427         int rc;
428
429         rte_spinlock_lock(&sfc_mae_switch.lock);
430
431         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
432         if (domain == NULL) {
433                 rc = EINVAL;
434                 goto fail_find_switch_domain_by_id;
435         }
436
437         port = sfc_mae_find_switch_port_by_entity(domain, req->entity_mportp,
438                                                   req->type);
439         if (port != NULL)
440                 goto done;
441
442         port = rte_zmalloc("sfc_mae_switch_port", sizeof(*port), 0);
443         if (port == NULL) {
444                 rc = ENOMEM;
445                 goto fail_mem_alloc;
446         }
447
448         port->entity_mport.sel = req->entity_mportp->sel;
449         port->type = req->type;
450
451         port->id = (domain->nb_ports++);
452
453         TAILQ_INSERT_TAIL(&domain->ports, port, switch_domain_ports);
454
455 done:
456         port->ethdev_mport = *req->ethdev_mportp;
457         port->ethdev_port_id = req->ethdev_port_id;
458
459         memcpy(&port->data, &req->port_data,
460                sizeof(port->data));
461
462         switch (req->type) {
463         case SFC_MAE_SWITCH_PORT_INDEPENDENT:
464                 if (port->data.indep.mae_admin) {
465                         SFC_ASSERT(domain->mae_admin_port == NULL);
466                         domain->mae_admin_port = port;
467                 }
468                 break;
469         case SFC_MAE_SWITCH_PORT_REPRESENTOR:
470                 break;
471         default:
472                 SFC_ASSERT(B_FALSE);
473         }
474
475         *switch_port_id = port->id;
476
477         rte_spinlock_unlock(&sfc_mae_switch.lock);
478
479         return 0;
480
481 fail_mem_alloc:
482 fail_find_switch_domain_by_id:
483         rte_spinlock_unlock(&sfc_mae_switch.lock);
484         return rc;
485 }
486
487 int
488 sfc_mae_clear_switch_port(uint16_t switch_domain_id,
489                           uint16_t switch_port_id)
490 {
491         struct sfc_mae_switch_domain *domain;
492
493         rte_spinlock_lock(&sfc_mae_switch.lock);
494
495         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
496         if (domain == NULL) {
497                 rte_spinlock_unlock(&sfc_mae_switch.lock);
498                 return EINVAL;
499         }
500
501         if (domain->mae_admin_port != NULL &&
502             domain->mae_admin_port->id == switch_port_id) {
503                 domain->mae_admin_port->data.indep.mae_admin = B_FALSE;
504                 domain->mae_admin_port = NULL;
505         }
506
507         rte_spinlock_unlock(&sfc_mae_switch.lock);
508         return 0;
509 }
510
511 /* This function expects to be called only when the lock is held */
512 static int
513 sfc_mae_find_switch_port_by_ethdev(uint16_t switch_domain_id,
514                                    uint16_t ethdev_port_id,
515                                    struct sfc_mae_switch_port **switch_port)
516 {
517         struct sfc_mae_switch_domain *domain;
518         struct sfc_mae_switch_port *port;
519
520         SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
521
522         if (ethdev_port_id == RTE_MAX_ETHPORTS)
523                 return EINVAL;
524
525         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
526         if (domain == NULL)
527                 return EINVAL;
528
529         TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
530                 if (port->ethdev_port_id == ethdev_port_id) {
531                         *switch_port = port;
532                         return 0;
533                 }
534         }
535
536         return ENOENT;
537 }
538
539 int
540 sfc_mae_switch_get_ethdev_mport(uint16_t switch_domain_id,
541                                 uint16_t ethdev_port_id,
542                                 efx_mport_sel_t *mport_sel)
543 {
544         struct sfc_mae_switch_port *port;
545         int rc;
546
547         rte_spinlock_lock(&sfc_mae_switch.lock);
548         rc = sfc_mae_find_switch_port_by_ethdev(switch_domain_id,
549                                                 ethdev_port_id, &port);
550         if (rc != 0)
551                 goto unlock;
552
553         if (port->type != SFC_MAE_SWITCH_PORT_INDEPENDENT) {
554                 /*
555                  * The ethdev is a "VF representor". It does not own
556                  * a dedicated m-port suitable for use in flow rules.
557                  */
558                 rc = ENOTSUP;
559                 goto unlock;
560         }
561
562         *mport_sel = port->ethdev_mport;
563
564 unlock:
565         rte_spinlock_unlock(&sfc_mae_switch.lock);
566
567         return rc;
568 }
569
570 int
571 sfc_mae_switch_get_entity_mport(uint16_t switch_domain_id,
572                                 uint16_t ethdev_port_id,
573                                 efx_mport_sel_t *mport_sel)
574 {
575         static struct sfc_mae_switch_port *port;
576         int rc;
577
578         rte_spinlock_lock(&sfc_mae_switch.lock);
579         rc = sfc_mae_find_switch_port_by_ethdev(switch_domain_id,
580                                                 ethdev_port_id, &port);
581         if (rc != 0)
582                 goto unlock;
583
584         if (port->type == SFC_MAE_SWITCH_PORT_INDEPENDENT &&
585             !port->data.indep.mae_admin) {
586                 /* See sfc_mae_assign_entity_mport() */
587                 rc = ENOTSUP;
588                 goto unlock;
589         }
590
591         *mport_sel = port->entity_mport;
592
593 unlock:
594         rte_spinlock_unlock(&sfc_mae_switch.lock);
595
596         return rc;
597 }
598
599 int
600 sfc_mae_switch_port_id_by_entity(uint16_t switch_domain_id,
601                                  const efx_mport_sel_t *entity_mportp,
602                                  enum sfc_mae_switch_port_type type,
603                                  uint16_t *switch_port_id)
604 {
605         int rc;
606
607         rte_spinlock_lock(&sfc_mae_switch.lock);
608         rc = sfc_mae_find_switch_port_id_by_entity(switch_domain_id,
609                                                    entity_mportp, type,
610                                                    switch_port_id);
611         rte_spinlock_unlock(&sfc_mae_switch.lock);
612
613         return rc;
614 }
615
616 static int
617 sfc_mae_get_switch_domain_admin_locked(uint16_t switch_domain_id,
618                                        uint16_t *port_id)
619 {
620         struct sfc_mae_switch_domain *domain;
621
622         SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
623
624         domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
625         if (domain == NULL)
626                 return EINVAL;
627
628         if (domain->mae_admin_port != NULL) {
629                 *port_id = domain->mae_admin_port->ethdev_port_id;
630                 return 0;
631         }
632
633         return ENOENT;
634 }
635
636 int
637 sfc_mae_get_switch_domain_admin(uint16_t switch_domain_id,
638                                 uint16_t *port_id)
639 {
640         int rc;
641
642         rte_spinlock_lock(&sfc_mae_switch.lock);
643         rc = sfc_mae_get_switch_domain_admin_locked(switch_domain_id, port_id);
644         rte_spinlock_unlock(&sfc_mae_switch.lock);
645         return rc;
646 }