11e7fbdf0SIvan Malov /* SPDX-License-Identifier: BSD-3-Clause
21e7fbdf0SIvan Malov *
398d26ef7SAndrew Rybchenko * Copyright(c) 2019-2021 Xilinx, Inc.
41e7fbdf0SIvan Malov * Copyright(c) 2019 Solarflare Communications Inc.
51e7fbdf0SIvan Malov *
61e7fbdf0SIvan Malov * This software was jointly developed between OKTET Labs (under contract
71e7fbdf0SIvan Malov * for Solarflare) and Solarflare Communications, Inc.
81e7fbdf0SIvan Malov */
91e7fbdf0SIvan Malov
101e7fbdf0SIvan Malov #include <stdbool.h>
111e7fbdf0SIvan Malov
121e7fbdf0SIvan Malov #include <rte_common.h>
131e7fbdf0SIvan Malov #include <rte_spinlock.h>
141e7fbdf0SIvan Malov
151e7fbdf0SIvan Malov #include "efx.h"
161e7fbdf0SIvan Malov
171e7fbdf0SIvan Malov #include "sfc.h"
181e7fbdf0SIvan Malov #include "sfc_log.h"
191e7fbdf0SIvan Malov #include "sfc_switch.h"
201e7fbdf0SIvan Malov
211e7fbdf0SIvan Malov /**
221e7fbdf0SIvan Malov * Switch port registry entry.
231e7fbdf0SIvan Malov *
241e7fbdf0SIvan Malov * Drivers aware of RTE switch domains also have to maintain RTE switch
251e7fbdf0SIvan Malov * port IDs for RTE ethdev instances they operate. These IDs are supposed
261e7fbdf0SIvan Malov * to stand for physical interconnect entities, in example, PCIe functions.
271e7fbdf0SIvan Malov *
281e7fbdf0SIvan Malov * In terms of MAE, a physical interconnect entity can be referred to using
291e7fbdf0SIvan Malov * an MPORT selector, that is, a 32-bit value. RTE switch port IDs, in turn,
301e7fbdf0SIvan Malov * are 16-bit values, so indirect mapping has to be maintained:
311e7fbdf0SIvan Malov *
321e7fbdf0SIvan Malov * +--------------------+ +---------------------------------------+
331e7fbdf0SIvan Malov * | RTE switch port ID | ------ | MAE switch port entry |
341e7fbdf0SIvan Malov * +--------------------+ | --------------------- |
351e7fbdf0SIvan Malov * | |
361e7fbdf0SIvan Malov * | Entity (PCIe function) MPORT selector |
371e7fbdf0SIvan Malov * | + |
381e7fbdf0SIvan Malov * | Port type (independent/representor) |
391e7fbdf0SIvan Malov * +---------------------------------------+
401e7fbdf0SIvan Malov *
411e7fbdf0SIvan Malov * This mapping comprises a port type to ensure that RTE switch port ID
421e7fbdf0SIvan Malov * of a represented entity and that of its representor are different in
431e7fbdf0SIvan Malov * the case when the entity gets plugged into DPDK and not into a guest.
441fb65e4dSIvan Malov *
451fb65e4dSIvan Malov * Entry data also comprises RTE ethdev's own MPORT. This value
461fb65e4dSIvan Malov * coincides with the entity MPORT in the case of independent ports.
471fb65e4dSIvan Malov * In the case of representors, this ID is not a selector and refers
481fb65e4dSIvan Malov * to an allocatable object (that is, it's likely to change on RTE
491fb65e4dSIvan Malov * ethdev replug). Flow API backend must use this value rather
501fb65e4dSIvan Malov * than entity_mport to support flow rule action PORT_ID.
511e7fbdf0SIvan Malov */
521e7fbdf0SIvan Malov struct sfc_mae_switch_port {
531e7fbdf0SIvan Malov TAILQ_ENTRY(sfc_mae_switch_port) switch_domain_ports;
541e7fbdf0SIvan Malov
551fb65e4dSIvan Malov /** RTE ethdev MPORT */
561fb65e4dSIvan Malov efx_mport_sel_t ethdev_mport;
571fb65e4dSIvan Malov /** RTE ethdev port ID */
581fb65e4dSIvan Malov uint16_t ethdev_port_id;
591fb65e4dSIvan Malov
601e7fbdf0SIvan Malov /** Entity (PCIe function) MPORT selector */
611e7fbdf0SIvan Malov efx_mport_sel_t entity_mport;
621e7fbdf0SIvan Malov /** Port type (independent/representor) */
631e7fbdf0SIvan Malov enum sfc_mae_switch_port_type type;
641e7fbdf0SIvan Malov /** RTE switch port ID */
651e7fbdf0SIvan Malov uint16_t id;
66768d1e44SViacheslav Galaktionov
67768d1e44SViacheslav Galaktionov union sfc_mae_switch_port_data data;
681e7fbdf0SIvan Malov };
691e7fbdf0SIvan Malov
701e7fbdf0SIvan Malov TAILQ_HEAD(sfc_mae_switch_ports, sfc_mae_switch_port);
711e7fbdf0SIvan Malov
721e7fbdf0SIvan Malov /**
731e7fbdf0SIvan Malov * Switch domain registry entry.
741e7fbdf0SIvan Malov *
751e7fbdf0SIvan Malov * Even if an RTE ethdev instance gets unplugged, the corresponding
761e7fbdf0SIvan Malov * entry in the switch port registry will not be removed because the
771e7fbdf0SIvan Malov * entity (PCIe function) MPORT is static and cannot change. If this
781e7fbdf0SIvan Malov * RTE ethdev gets plugged back, the entry will be reused, and
791e7fbdf0SIvan Malov * RTE switch port ID will be the same.
801e7fbdf0SIvan Malov */
811e7fbdf0SIvan Malov struct sfc_mae_switch_domain {
821e7fbdf0SIvan Malov TAILQ_ENTRY(sfc_mae_switch_domain) entries;
831e7fbdf0SIvan Malov
841e7fbdf0SIvan Malov /** HW switch ID */
851e7fbdf0SIvan Malov struct sfc_hw_switch_id *hw_switch_id;
861e7fbdf0SIvan Malov /** The number of ports in the switch port registry */
871e7fbdf0SIvan Malov unsigned int nb_ports;
881e7fbdf0SIvan Malov /** Switch port registry */
891e7fbdf0SIvan Malov struct sfc_mae_switch_ports ports;
901e7fbdf0SIvan Malov /** RTE switch domain ID allocated for a group of devices */
911e7fbdf0SIvan Malov uint16_t id;
9244db08d5SViacheslav Galaktionov /** DPDK controller -> EFX interface mapping */
9344db08d5SViacheslav Galaktionov efx_pcie_interface_t *controllers;
9444db08d5SViacheslav Galaktionov /** Number of DPDK controllers and EFX interfaces */
9544db08d5SViacheslav Galaktionov size_t nb_controllers;
9626706314SViacheslav Galaktionov /** MAE admin port */
9726706314SViacheslav Galaktionov struct sfc_mae_switch_port *mae_admin_port;
981e7fbdf0SIvan Malov };
991e7fbdf0SIvan Malov
1001e7fbdf0SIvan Malov TAILQ_HEAD(sfc_mae_switch_domains, sfc_mae_switch_domain);
1011e7fbdf0SIvan Malov
1021e7fbdf0SIvan Malov /**
1031e7fbdf0SIvan Malov * MAE representation of RTE switch infrastructure.
1041e7fbdf0SIvan Malov *
1051e7fbdf0SIvan Malov * It is possible that an RTE flow API client tries to insert a rule
1061e7fbdf0SIvan Malov * referencing an RTE ethdev deployed on top of a different physical
1071e7fbdf0SIvan Malov * device (it may belong to the same vendor or not). This particular
1081e7fbdf0SIvan Malov * driver/engine cannot support this and has to turn down such rules.
1091e7fbdf0SIvan Malov *
1101e7fbdf0SIvan Malov * Technically, it's HW switch identifier which, if queried for each
1111e7fbdf0SIvan Malov * RTE ethdev instance, indicates relationship between the instances.
1121e7fbdf0SIvan Malov * In the meantime, RTE flow API clients also need to somehow figure
1131e7fbdf0SIvan Malov * out relationship between RTE ethdev instances in advance.
1141e7fbdf0SIvan Malov *
1151e7fbdf0SIvan Malov * The concept of RTE switch domains resolves this issue. The driver
1161e7fbdf0SIvan Malov * maintains a static list of switch domains which is easy to browse,
1171e7fbdf0SIvan Malov * and each RTE ethdev fills RTE switch parameters in device
1181e7fbdf0SIvan Malov * information structure which is made available to clients.
1191e7fbdf0SIvan Malov *
1201e7fbdf0SIvan Malov * Even if all RTE ethdev instances belonging to a switch domain get
1211e7fbdf0SIvan Malov * unplugged, the corresponding entry in the switch domain registry
1221e7fbdf0SIvan Malov * will not be removed because the corresponding HW switch exists
1231e7fbdf0SIvan Malov * regardless of its ports being plugged to DPDK or kept aside.
1241e7fbdf0SIvan Malov * If a port gets plugged back to DPDK, the corresponding
1251e7fbdf0SIvan Malov * RTE ethdev will indicate the same RTE switch domain ID.
1261e7fbdf0SIvan Malov */
1271e7fbdf0SIvan Malov struct sfc_mae_switch {
1281e7fbdf0SIvan Malov /** A lock to protect the whole structure */
1291e7fbdf0SIvan Malov rte_spinlock_t lock;
1301e7fbdf0SIvan Malov /** Switch domain registry */
1311e7fbdf0SIvan Malov struct sfc_mae_switch_domains domains;
1321e7fbdf0SIvan Malov };
1331e7fbdf0SIvan Malov
1341e7fbdf0SIvan Malov static struct sfc_mae_switch sfc_mae_switch = {
1351e7fbdf0SIvan Malov .lock = RTE_SPINLOCK_INITIALIZER,
1361e7fbdf0SIvan Malov .domains = TAILQ_HEAD_INITIALIZER(sfc_mae_switch.domains),
1371e7fbdf0SIvan Malov };
1381e7fbdf0SIvan Malov
1391e7fbdf0SIvan Malov
1401e7fbdf0SIvan Malov /* This function expects to be called only when the lock is held */
1411e7fbdf0SIvan Malov static struct sfc_mae_switch_domain *
sfc_mae_find_switch_domain_by_id(uint16_t switch_domain_id)1421e7fbdf0SIvan Malov sfc_mae_find_switch_domain_by_id(uint16_t switch_domain_id)
1431e7fbdf0SIvan Malov {
1441e7fbdf0SIvan Malov struct sfc_mae_switch_domain *domain;
1451e7fbdf0SIvan Malov
1461e7fbdf0SIvan Malov SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
1471e7fbdf0SIvan Malov
1481e7fbdf0SIvan Malov TAILQ_FOREACH(domain, &sfc_mae_switch.domains, entries) {
1491e7fbdf0SIvan Malov if (domain->id == switch_domain_id)
1501e7fbdf0SIvan Malov return domain;
1511e7fbdf0SIvan Malov }
1521e7fbdf0SIvan Malov
1531e7fbdf0SIvan Malov return NULL;
1541e7fbdf0SIvan Malov }
1551e7fbdf0SIvan Malov
156599e4e9aSViacheslav Galaktionov int
sfc_mae_switch_ports_iterate(uint16_t switch_domain_id,sfc_mae_switch_port_iterator_cb * cb,void * data)157599e4e9aSViacheslav Galaktionov sfc_mae_switch_ports_iterate(uint16_t switch_domain_id,
158599e4e9aSViacheslav Galaktionov sfc_mae_switch_port_iterator_cb *cb,
159599e4e9aSViacheslav Galaktionov void *data)
160599e4e9aSViacheslav Galaktionov {
161599e4e9aSViacheslav Galaktionov struct sfc_mae_switch_domain *domain;
162599e4e9aSViacheslav Galaktionov struct sfc_mae_switch_port *port;
163599e4e9aSViacheslav Galaktionov
164599e4e9aSViacheslav Galaktionov if (cb == NULL)
165599e4e9aSViacheslav Galaktionov return EINVAL;
166599e4e9aSViacheslav Galaktionov
167599e4e9aSViacheslav Galaktionov rte_spinlock_lock(&sfc_mae_switch.lock);
168599e4e9aSViacheslav Galaktionov
169599e4e9aSViacheslav Galaktionov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
170599e4e9aSViacheslav Galaktionov if (domain == NULL) {
171599e4e9aSViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
172599e4e9aSViacheslav Galaktionov return EINVAL;
173599e4e9aSViacheslav Galaktionov }
174599e4e9aSViacheslav Galaktionov
175599e4e9aSViacheslav Galaktionov TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
176599e4e9aSViacheslav Galaktionov cb(port->type, &port->ethdev_mport, port->ethdev_port_id,
177599e4e9aSViacheslav Galaktionov &port->entity_mport, port->id, &port->data, data);
178599e4e9aSViacheslav Galaktionov }
179599e4e9aSViacheslav Galaktionov
180599e4e9aSViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
181599e4e9aSViacheslav Galaktionov return 0;
182599e4e9aSViacheslav Galaktionov }
183599e4e9aSViacheslav Galaktionov
1841e7fbdf0SIvan Malov /* This function expects to be called only when the lock is held */
1851e7fbdf0SIvan Malov static struct sfc_mae_switch_domain *
sfc_mae_find_switch_domain_by_hw_switch_id(const struct sfc_hw_switch_id * id)1861e7fbdf0SIvan Malov sfc_mae_find_switch_domain_by_hw_switch_id(const struct sfc_hw_switch_id *id)
1871e7fbdf0SIvan Malov {
1881e7fbdf0SIvan Malov struct sfc_mae_switch_domain *domain;
1891e7fbdf0SIvan Malov
1901e7fbdf0SIvan Malov SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
1911e7fbdf0SIvan Malov
1921e7fbdf0SIvan Malov TAILQ_FOREACH(domain, &sfc_mae_switch.domains, entries) {
1931e7fbdf0SIvan Malov if (sfc_hw_switch_ids_equal(domain->hw_switch_id, id))
1941e7fbdf0SIvan Malov return domain;
1951e7fbdf0SIvan Malov }
1961e7fbdf0SIvan Malov
1971e7fbdf0SIvan Malov return NULL;
1981e7fbdf0SIvan Malov }
1991e7fbdf0SIvan Malov
2001e7fbdf0SIvan Malov int
sfc_mae_assign_switch_domain(struct sfc_adapter * sa,uint16_t * switch_domain_id)2011e7fbdf0SIvan Malov sfc_mae_assign_switch_domain(struct sfc_adapter *sa,
2021e7fbdf0SIvan Malov uint16_t *switch_domain_id)
2031e7fbdf0SIvan Malov {
2041e7fbdf0SIvan Malov struct sfc_hw_switch_id *hw_switch_id;
2051e7fbdf0SIvan Malov struct sfc_mae_switch_domain *domain;
2061e7fbdf0SIvan Malov int rc;
2071e7fbdf0SIvan Malov
2081e7fbdf0SIvan Malov rte_spinlock_lock(&sfc_mae_switch.lock);
2091e7fbdf0SIvan Malov
2101e7fbdf0SIvan Malov rc = sfc_hw_switch_id_init(sa, &hw_switch_id);
2111e7fbdf0SIvan Malov if (rc != 0)
2121e7fbdf0SIvan Malov goto fail_hw_switch_id_init;
2131e7fbdf0SIvan Malov
2141e7fbdf0SIvan Malov domain = sfc_mae_find_switch_domain_by_hw_switch_id(hw_switch_id);
2151e7fbdf0SIvan Malov if (domain != NULL) {
2161e7fbdf0SIvan Malov sfc_hw_switch_id_fini(sa, hw_switch_id);
2171e7fbdf0SIvan Malov goto done;
2181e7fbdf0SIvan Malov }
2191e7fbdf0SIvan Malov
2201e7fbdf0SIvan Malov domain = rte_zmalloc("sfc_mae_switch_domain", sizeof(*domain), 0);
2211e7fbdf0SIvan Malov if (domain == NULL) {
2221e7fbdf0SIvan Malov rc = ENOMEM;
2231e7fbdf0SIvan Malov goto fail_mem_alloc;
2241e7fbdf0SIvan Malov }
2251e7fbdf0SIvan Malov
2261e7fbdf0SIvan Malov /*
2271e7fbdf0SIvan Malov * This code belongs to driver init path, that is, negation is
2281e7fbdf0SIvan Malov * done at the end of the path by sfc_eth_dev_init(). RTE APIs
2291e7fbdf0SIvan Malov * negate error codes, so drop negation here.
2301e7fbdf0SIvan Malov */
2311e7fbdf0SIvan Malov rc = -rte_eth_switch_domain_alloc(&domain->id);
2321e7fbdf0SIvan Malov if (rc != 0)
2331e7fbdf0SIvan Malov goto fail_domain_alloc;
2341e7fbdf0SIvan Malov
2351e7fbdf0SIvan Malov domain->hw_switch_id = hw_switch_id;
2361e7fbdf0SIvan Malov
2371e7fbdf0SIvan Malov TAILQ_INIT(&domain->ports);
2381e7fbdf0SIvan Malov
2391e7fbdf0SIvan Malov TAILQ_INSERT_TAIL(&sfc_mae_switch.domains, domain, entries);
2401e7fbdf0SIvan Malov
2411e7fbdf0SIvan Malov done:
2421e7fbdf0SIvan Malov *switch_domain_id = domain->id;
2431e7fbdf0SIvan Malov
2441e7fbdf0SIvan Malov rte_spinlock_unlock(&sfc_mae_switch.lock);
2451e7fbdf0SIvan Malov
2461e7fbdf0SIvan Malov return 0;
2471e7fbdf0SIvan Malov
2481e7fbdf0SIvan Malov fail_domain_alloc:
2491e7fbdf0SIvan Malov rte_free(domain);
2501e7fbdf0SIvan Malov
2511e7fbdf0SIvan Malov fail_mem_alloc:
2521e7fbdf0SIvan Malov sfc_hw_switch_id_fini(sa, hw_switch_id);
2531e7fbdf0SIvan Malov
2541e7fbdf0SIvan Malov fail_hw_switch_id_init:
255c7e64eeaSViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
2561e7fbdf0SIvan Malov return rc;
2571e7fbdf0SIvan Malov }
2581e7fbdf0SIvan Malov
25944db08d5SViacheslav Galaktionov int
sfc_mae_switch_domain_controllers(uint16_t switch_domain_id,const efx_pcie_interface_t ** controllers,size_t * nb_controllers)26044db08d5SViacheslav Galaktionov sfc_mae_switch_domain_controllers(uint16_t switch_domain_id,
26144db08d5SViacheslav Galaktionov const efx_pcie_interface_t **controllers,
26244db08d5SViacheslav Galaktionov size_t *nb_controllers)
26344db08d5SViacheslav Galaktionov {
26444db08d5SViacheslav Galaktionov struct sfc_mae_switch_domain *domain;
26544db08d5SViacheslav Galaktionov
26644db08d5SViacheslav Galaktionov if (controllers == NULL || nb_controllers == NULL)
26744db08d5SViacheslav Galaktionov return EINVAL;
26844db08d5SViacheslav Galaktionov
26944db08d5SViacheslav Galaktionov rte_spinlock_lock(&sfc_mae_switch.lock);
27044db08d5SViacheslav Galaktionov
27144db08d5SViacheslav Galaktionov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
27244db08d5SViacheslav Galaktionov if (domain == NULL) {
27344db08d5SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
27444db08d5SViacheslav Galaktionov return EINVAL;
27544db08d5SViacheslav Galaktionov }
27644db08d5SViacheslav Galaktionov
27744db08d5SViacheslav Galaktionov *controllers = domain->controllers;
27844db08d5SViacheslav Galaktionov *nb_controllers = domain->nb_controllers;
27944db08d5SViacheslav Galaktionov
28044db08d5SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
28144db08d5SViacheslav Galaktionov return 0;
28244db08d5SViacheslav Galaktionov }
28344db08d5SViacheslav Galaktionov
28444db08d5SViacheslav Galaktionov int
sfc_mae_switch_domain_map_controllers(uint16_t switch_domain_id,efx_pcie_interface_t * controllers,size_t nb_controllers)28544db08d5SViacheslav Galaktionov sfc_mae_switch_domain_map_controllers(uint16_t switch_domain_id,
28644db08d5SViacheslav Galaktionov efx_pcie_interface_t *controllers,
28744db08d5SViacheslav Galaktionov size_t nb_controllers)
28844db08d5SViacheslav Galaktionov {
28944db08d5SViacheslav Galaktionov struct sfc_mae_switch_domain *domain;
29044db08d5SViacheslav Galaktionov
29144db08d5SViacheslav Galaktionov rte_spinlock_lock(&sfc_mae_switch.lock);
29244db08d5SViacheslav Galaktionov
29344db08d5SViacheslav Galaktionov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
29444db08d5SViacheslav Galaktionov if (domain == NULL) {
29544db08d5SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
29644db08d5SViacheslav Galaktionov return EINVAL;
29744db08d5SViacheslav Galaktionov }
29844db08d5SViacheslav Galaktionov
29944db08d5SViacheslav Galaktionov /* Controller mapping may be set only once */
30044db08d5SViacheslav Galaktionov if (domain->controllers != NULL) {
30144db08d5SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
30244db08d5SViacheslav Galaktionov return EINVAL;
30344db08d5SViacheslav Galaktionov }
30444db08d5SViacheslav Galaktionov
30544db08d5SViacheslav Galaktionov domain->controllers = controllers;
30644db08d5SViacheslav Galaktionov domain->nb_controllers = nb_controllers;
30744db08d5SViacheslav Galaktionov
30844db08d5SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
30944db08d5SViacheslav Galaktionov return 0;
31044db08d5SViacheslav Galaktionov }
31144db08d5SViacheslav Galaktionov
312c75d560dSViacheslav Galaktionov int
sfc_mae_switch_controller_from_mapping(const efx_pcie_interface_t * controllers,size_t nb_controllers,efx_pcie_interface_t intf,int * controller)313599e4e9aSViacheslav Galaktionov sfc_mae_switch_controller_from_mapping(const efx_pcie_interface_t *controllers,
314599e4e9aSViacheslav Galaktionov size_t nb_controllers,
315c75d560dSViacheslav Galaktionov efx_pcie_interface_t intf,
316c75d560dSViacheslav Galaktionov int *controller)
317c75d560dSViacheslav Galaktionov {
318c75d560dSViacheslav Galaktionov size_t i;
319c75d560dSViacheslav Galaktionov
320c75d560dSViacheslav Galaktionov if (controllers == NULL)
321c75d560dSViacheslav Galaktionov return ENOENT;
322c75d560dSViacheslav Galaktionov
323c75d560dSViacheslav Galaktionov for (i = 0; i < nb_controllers; i++) {
324c75d560dSViacheslav Galaktionov if (controllers[i] == intf) {
325c75d560dSViacheslav Galaktionov *controller = i;
326c75d560dSViacheslav Galaktionov return 0;
327c75d560dSViacheslav Galaktionov }
328c75d560dSViacheslav Galaktionov }
329c75d560dSViacheslav Galaktionov
330c75d560dSViacheslav Galaktionov return ENOENT;
331c75d560dSViacheslav Galaktionov }
332c75d560dSViacheslav Galaktionov
333599e4e9aSViacheslav Galaktionov int
sfc_mae_switch_domain_get_controller(uint16_t switch_domain_id,efx_pcie_interface_t intf,int * controller)334599e4e9aSViacheslav Galaktionov sfc_mae_switch_domain_get_controller(uint16_t switch_domain_id,
335599e4e9aSViacheslav Galaktionov efx_pcie_interface_t intf,
336599e4e9aSViacheslav Galaktionov int *controller)
337599e4e9aSViacheslav Galaktionov {
338599e4e9aSViacheslav Galaktionov const efx_pcie_interface_t *controllers;
339599e4e9aSViacheslav Galaktionov size_t nb_controllers;
340599e4e9aSViacheslav Galaktionov int rc;
341599e4e9aSViacheslav Galaktionov
342599e4e9aSViacheslav Galaktionov rc = sfc_mae_switch_domain_controllers(switch_domain_id, &controllers,
343599e4e9aSViacheslav Galaktionov &nb_controllers);
344599e4e9aSViacheslav Galaktionov if (rc != 0)
345599e4e9aSViacheslav Galaktionov return rc;
346599e4e9aSViacheslav Galaktionov
347599e4e9aSViacheslav Galaktionov return sfc_mae_switch_controller_from_mapping(controllers,
348599e4e9aSViacheslav Galaktionov nb_controllers,
349599e4e9aSViacheslav Galaktionov intf,
350599e4e9aSViacheslav Galaktionov controller);
351599e4e9aSViacheslav Galaktionov }
352599e4e9aSViacheslav Galaktionov
sfc_mae_switch_domain_get_intf(uint16_t switch_domain_id,int controller,efx_pcie_interface_t * intf)3536ded2e01SViacheslav Galaktionov int sfc_mae_switch_domain_get_intf(uint16_t switch_domain_id,
3546ded2e01SViacheslav Galaktionov int controller,
3556ded2e01SViacheslav Galaktionov efx_pcie_interface_t *intf)
3566ded2e01SViacheslav Galaktionov {
3576ded2e01SViacheslav Galaktionov const efx_pcie_interface_t *controllers;
3586ded2e01SViacheslav Galaktionov size_t nb_controllers;
3596ded2e01SViacheslav Galaktionov int rc;
3606ded2e01SViacheslav Galaktionov
3616ded2e01SViacheslav Galaktionov rc = sfc_mae_switch_domain_controllers(switch_domain_id, &controllers,
3626ded2e01SViacheslav Galaktionov &nb_controllers);
3636ded2e01SViacheslav Galaktionov if (rc != 0)
3646ded2e01SViacheslav Galaktionov return rc;
3656ded2e01SViacheslav Galaktionov
3666ded2e01SViacheslav Galaktionov if (controllers == NULL)
3676ded2e01SViacheslav Galaktionov return ENOENT;
3686ded2e01SViacheslav Galaktionov
3696ded2e01SViacheslav Galaktionov if ((size_t)controller > nb_controllers)
3706ded2e01SViacheslav Galaktionov return EINVAL;
3716ded2e01SViacheslav Galaktionov
3726ded2e01SViacheslav Galaktionov *intf = controllers[controller];
3736ded2e01SViacheslav Galaktionov
3746ded2e01SViacheslav Galaktionov return 0;
3756ded2e01SViacheslav Galaktionov }
3766ded2e01SViacheslav Galaktionov
3771e7fbdf0SIvan Malov /* This function expects to be called only when the lock is held */
3781e7fbdf0SIvan Malov static struct sfc_mae_switch_port *
sfc_mae_find_switch_port_by_entity(const struct sfc_mae_switch_domain * domain,const efx_mport_sel_t * entity_mportp,enum sfc_mae_switch_port_type type)3791e7fbdf0SIvan Malov sfc_mae_find_switch_port_by_entity(const struct sfc_mae_switch_domain *domain,
3801e7fbdf0SIvan Malov const efx_mport_sel_t *entity_mportp,
3811e7fbdf0SIvan Malov enum sfc_mae_switch_port_type type)
3821e7fbdf0SIvan Malov {
3831e7fbdf0SIvan Malov struct sfc_mae_switch_port *port;
3841e7fbdf0SIvan Malov
3851e7fbdf0SIvan Malov SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
3861e7fbdf0SIvan Malov
3871e7fbdf0SIvan Malov TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
3881e7fbdf0SIvan Malov if (port->entity_mport.sel == entity_mportp->sel &&
3891e7fbdf0SIvan Malov port->type == type)
3901e7fbdf0SIvan Malov return port;
3911e7fbdf0SIvan Malov }
3921e7fbdf0SIvan Malov
3931e7fbdf0SIvan Malov return NULL;
3941e7fbdf0SIvan Malov }
3951e7fbdf0SIvan Malov
396599e4e9aSViacheslav Galaktionov /* This function expects to be called only when the lock is held */
397599e4e9aSViacheslav Galaktionov static int
sfc_mae_find_switch_port_id_by_entity(uint16_t switch_domain_id,const efx_mport_sel_t * entity_mportp,enum sfc_mae_switch_port_type type,uint16_t * switch_port_id)398599e4e9aSViacheslav Galaktionov sfc_mae_find_switch_port_id_by_entity(uint16_t switch_domain_id,
399599e4e9aSViacheslav Galaktionov const efx_mport_sel_t *entity_mportp,
400599e4e9aSViacheslav Galaktionov enum sfc_mae_switch_port_type type,
401599e4e9aSViacheslav Galaktionov uint16_t *switch_port_id)
402599e4e9aSViacheslav Galaktionov {
403599e4e9aSViacheslav Galaktionov struct sfc_mae_switch_domain *domain;
404599e4e9aSViacheslav Galaktionov struct sfc_mae_switch_port *port;
405599e4e9aSViacheslav Galaktionov
406599e4e9aSViacheslav Galaktionov SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
407599e4e9aSViacheslav Galaktionov
408599e4e9aSViacheslav Galaktionov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
409599e4e9aSViacheslav Galaktionov if (domain == NULL)
410599e4e9aSViacheslav Galaktionov return EINVAL;
411599e4e9aSViacheslav Galaktionov
412599e4e9aSViacheslav Galaktionov port = sfc_mae_find_switch_port_by_entity(domain, entity_mportp, type);
413599e4e9aSViacheslav Galaktionov if (port == NULL)
414599e4e9aSViacheslav Galaktionov return ENOENT;
415599e4e9aSViacheslav Galaktionov
416599e4e9aSViacheslav Galaktionov *switch_port_id = port->id;
417599e4e9aSViacheslav Galaktionov return 0;
418599e4e9aSViacheslav Galaktionov }
419599e4e9aSViacheslav Galaktionov
4201e7fbdf0SIvan Malov int
sfc_mae_assign_switch_port(uint16_t switch_domain_id,const struct sfc_mae_switch_port_request * req,uint16_t * switch_port_id)4211e7fbdf0SIvan Malov sfc_mae_assign_switch_port(uint16_t switch_domain_id,
4221e7fbdf0SIvan Malov const struct sfc_mae_switch_port_request *req,
4231e7fbdf0SIvan Malov uint16_t *switch_port_id)
4241e7fbdf0SIvan Malov {
4251e7fbdf0SIvan Malov struct sfc_mae_switch_domain *domain;
4261e7fbdf0SIvan Malov struct sfc_mae_switch_port *port;
4271e7fbdf0SIvan Malov int rc;
4281e7fbdf0SIvan Malov
4291e7fbdf0SIvan Malov rte_spinlock_lock(&sfc_mae_switch.lock);
4301e7fbdf0SIvan Malov
4311e7fbdf0SIvan Malov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
4321e7fbdf0SIvan Malov if (domain == NULL) {
4331e7fbdf0SIvan Malov rc = EINVAL;
4341e7fbdf0SIvan Malov goto fail_find_switch_domain_by_id;
4351e7fbdf0SIvan Malov }
4361e7fbdf0SIvan Malov
4371e7fbdf0SIvan Malov port = sfc_mae_find_switch_port_by_entity(domain, req->entity_mportp,
4381e7fbdf0SIvan Malov req->type);
4391e7fbdf0SIvan Malov if (port != NULL)
4401e7fbdf0SIvan Malov goto done;
4411e7fbdf0SIvan Malov
4421e7fbdf0SIvan Malov port = rte_zmalloc("sfc_mae_switch_port", sizeof(*port), 0);
4431e7fbdf0SIvan Malov if (port == NULL) {
4441e7fbdf0SIvan Malov rc = ENOMEM;
4451e7fbdf0SIvan Malov goto fail_mem_alloc;
4461e7fbdf0SIvan Malov }
4471e7fbdf0SIvan Malov
4481e7fbdf0SIvan Malov port->entity_mport.sel = req->entity_mportp->sel;
4491e7fbdf0SIvan Malov port->type = req->type;
4501e7fbdf0SIvan Malov
4511e7fbdf0SIvan Malov port->id = (domain->nb_ports++);
4521e7fbdf0SIvan Malov
4531e7fbdf0SIvan Malov TAILQ_INSERT_TAIL(&domain->ports, port, switch_domain_ports);
4541e7fbdf0SIvan Malov
4551e7fbdf0SIvan Malov done:
4561fb65e4dSIvan Malov port->ethdev_mport = *req->ethdev_mportp;
4571fb65e4dSIvan Malov port->ethdev_port_id = req->ethdev_port_id;
4581fb65e4dSIvan Malov
45926706314SViacheslav Galaktionov memcpy(&port->data, &req->port_data,
46026706314SViacheslav Galaktionov sizeof(port->data));
46126706314SViacheslav Galaktionov
462768d1e44SViacheslav Galaktionov switch (req->type) {
463768d1e44SViacheslav Galaktionov case SFC_MAE_SWITCH_PORT_INDEPENDENT:
46426706314SViacheslav Galaktionov if (port->data.indep.mae_admin) {
46526706314SViacheslav Galaktionov SFC_ASSERT(domain->mae_admin_port == NULL);
46626706314SViacheslav Galaktionov domain->mae_admin_port = port;
46726706314SViacheslav Galaktionov }
468768d1e44SViacheslav Galaktionov break;
469768d1e44SViacheslav Galaktionov case SFC_MAE_SWITCH_PORT_REPRESENTOR:
470768d1e44SViacheslav Galaktionov break;
471768d1e44SViacheslav Galaktionov default:
472768d1e44SViacheslav Galaktionov SFC_ASSERT(B_FALSE);
473768d1e44SViacheslav Galaktionov }
474768d1e44SViacheslav Galaktionov
4751e7fbdf0SIvan Malov *switch_port_id = port->id;
4761e7fbdf0SIvan Malov
4771e7fbdf0SIvan Malov rte_spinlock_unlock(&sfc_mae_switch.lock);
4781e7fbdf0SIvan Malov
4791e7fbdf0SIvan Malov return 0;
4801e7fbdf0SIvan Malov
4811e7fbdf0SIvan Malov fail_mem_alloc:
4821e7fbdf0SIvan Malov fail_find_switch_domain_by_id:
4831e7fbdf0SIvan Malov rte_spinlock_unlock(&sfc_mae_switch.lock);
4841e7fbdf0SIvan Malov return rc;
4851e7fbdf0SIvan Malov }
4861fb65e4dSIvan Malov
48726706314SViacheslav Galaktionov int
sfc_mae_clear_switch_port(uint16_t switch_domain_id,uint16_t switch_port_id)48826706314SViacheslav Galaktionov sfc_mae_clear_switch_port(uint16_t switch_domain_id,
48926706314SViacheslav Galaktionov uint16_t switch_port_id)
49026706314SViacheslav Galaktionov {
49126706314SViacheslav Galaktionov struct sfc_mae_switch_domain *domain;
492723327beSIvan Malov struct sfc_mae_switch_port *port;
49326706314SViacheslav Galaktionov
49426706314SViacheslav Galaktionov rte_spinlock_lock(&sfc_mae_switch.lock);
49526706314SViacheslav Galaktionov
49626706314SViacheslav Galaktionov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
49726706314SViacheslav Galaktionov if (domain == NULL) {
49826706314SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
49926706314SViacheslav Galaktionov return EINVAL;
50026706314SViacheslav Galaktionov }
50126706314SViacheslav Galaktionov
50226706314SViacheslav Galaktionov if (domain->mae_admin_port != NULL &&
50326706314SViacheslav Galaktionov domain->mae_admin_port->id == switch_port_id) {
50426706314SViacheslav Galaktionov domain->mae_admin_port->data.indep.mae_admin = B_FALSE;
50526706314SViacheslav Galaktionov domain->mae_admin_port = NULL;
50626706314SViacheslav Galaktionov }
50726706314SViacheslav Galaktionov
508723327beSIvan Malov TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
509723327beSIvan Malov if (port->id == switch_port_id) {
510723327beSIvan Malov /*
511723327beSIvan Malov * Invalidate the field to prevent wrong
512723327beSIvan Malov * look-ups from flow rule handling path.
513723327beSIvan Malov */
514723327beSIvan Malov port->ethdev_port_id = RTE_MAX_ETHPORTS;
515723327beSIvan Malov break;
516723327beSIvan Malov }
517723327beSIvan Malov }
518723327beSIvan Malov
51926706314SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
52026706314SViacheslav Galaktionov return 0;
52126706314SViacheslav Galaktionov }
52226706314SViacheslav Galaktionov
5231fb65e4dSIvan Malov /* This function expects to be called only when the lock is held */
5241fb65e4dSIvan Malov static int
sfc_mae_find_switch_port_by_ethdev(uint16_t switch_domain_id,uint16_t ethdev_port_id,struct sfc_mae_switch_port ** switch_port)5251fb65e4dSIvan Malov sfc_mae_find_switch_port_by_ethdev(uint16_t switch_domain_id,
5261fb65e4dSIvan Malov uint16_t ethdev_port_id,
527b7b7b9f8SIvan Malov struct sfc_mae_switch_port **switch_port)
5281fb65e4dSIvan Malov {
5291fb65e4dSIvan Malov struct sfc_mae_switch_domain *domain;
5301fb65e4dSIvan Malov struct sfc_mae_switch_port *port;
5311fb65e4dSIvan Malov
5321fb65e4dSIvan Malov SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
5331fb65e4dSIvan Malov
5341fb65e4dSIvan Malov if (ethdev_port_id == RTE_MAX_ETHPORTS)
5351fb65e4dSIvan Malov return EINVAL;
5361fb65e4dSIvan Malov
5371fb65e4dSIvan Malov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
5381fb65e4dSIvan Malov if (domain == NULL)
5391fb65e4dSIvan Malov return EINVAL;
5401fb65e4dSIvan Malov
5411fb65e4dSIvan Malov TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
5421fb65e4dSIvan Malov if (port->ethdev_port_id == ethdev_port_id) {
543b7b7b9f8SIvan Malov *switch_port = port;
5441fb65e4dSIvan Malov return 0;
5451fb65e4dSIvan Malov }
5461fb65e4dSIvan Malov }
5471fb65e4dSIvan Malov
5481fb65e4dSIvan Malov return ENOENT;
5491fb65e4dSIvan Malov }
5501fb65e4dSIvan Malov
5511fb65e4dSIvan Malov int
sfc_mae_switch_get_ethdev_mport(uint16_t switch_domain_id,uint16_t ethdev_port_id,unsigned int allowed_mae_switch_port_types,efx_mport_sel_t * mport_sel)5523419c9a7SIvan Malov sfc_mae_switch_get_ethdev_mport(uint16_t switch_domain_id,
5531fb65e4dSIvan Malov uint16_t ethdev_port_id,
554*ef96f7ebSIvan Malov unsigned int allowed_mae_switch_port_types,
5551fb65e4dSIvan Malov efx_mport_sel_t *mport_sel)
5561fb65e4dSIvan Malov {
557b7b7b9f8SIvan Malov struct sfc_mae_switch_port *port;
5581fb65e4dSIvan Malov int rc;
5591fb65e4dSIvan Malov
5601fb65e4dSIvan Malov rte_spinlock_lock(&sfc_mae_switch.lock);
5611fb65e4dSIvan Malov rc = sfc_mae_find_switch_port_by_ethdev(switch_domain_id,
562b7b7b9f8SIvan Malov ethdev_port_id, &port);
563b7b7b9f8SIvan Malov if (rc != 0)
564b7b7b9f8SIvan Malov goto unlock;
565b7b7b9f8SIvan Malov
566*ef96f7ebSIvan Malov if (((1U << port->type) & allowed_mae_switch_port_types) == 0) {
567b7b7b9f8SIvan Malov rc = ENOTSUP;
568b7b7b9f8SIvan Malov goto unlock;
569b7b7b9f8SIvan Malov }
570b7b7b9f8SIvan Malov
571b7b7b9f8SIvan Malov *mport_sel = port->ethdev_mport;
572b7b7b9f8SIvan Malov
573b7b7b9f8SIvan Malov unlock:
5741fb65e4dSIvan Malov rte_spinlock_unlock(&sfc_mae_switch.lock);
5751fb65e4dSIvan Malov
5761fb65e4dSIvan Malov return rc;
5771fb65e4dSIvan Malov }
578599e4e9aSViacheslav Galaktionov
579599e4e9aSViacheslav Galaktionov int
sfc_mae_switch_get_entity_mport(uint16_t switch_domain_id,uint16_t ethdev_port_id,efx_mport_sel_t * mport_sel)5800fb3e8a9SIvan Malov sfc_mae_switch_get_entity_mport(uint16_t switch_domain_id,
5810fb3e8a9SIvan Malov uint16_t ethdev_port_id,
5820fb3e8a9SIvan Malov efx_mport_sel_t *mport_sel)
5830fb3e8a9SIvan Malov {
5840fb3e8a9SIvan Malov static struct sfc_mae_switch_port *port;
5850fb3e8a9SIvan Malov int rc;
5860fb3e8a9SIvan Malov
5870fb3e8a9SIvan Malov rte_spinlock_lock(&sfc_mae_switch.lock);
5880fb3e8a9SIvan Malov rc = sfc_mae_find_switch_port_by_ethdev(switch_domain_id,
5890fb3e8a9SIvan Malov ethdev_port_id, &port);
5900fb3e8a9SIvan Malov if (rc != 0)
5910fb3e8a9SIvan Malov goto unlock;
5920fb3e8a9SIvan Malov
5930fb3e8a9SIvan Malov if (port->type == SFC_MAE_SWITCH_PORT_INDEPENDENT &&
5940fb3e8a9SIvan Malov !port->data.indep.mae_admin) {
5950fb3e8a9SIvan Malov /* See sfc_mae_assign_entity_mport() */
5960fb3e8a9SIvan Malov rc = ENOTSUP;
5970fb3e8a9SIvan Malov goto unlock;
5980fb3e8a9SIvan Malov }
5990fb3e8a9SIvan Malov
6000fb3e8a9SIvan Malov *mport_sel = port->entity_mport;
6010fb3e8a9SIvan Malov
6020fb3e8a9SIvan Malov unlock:
6030fb3e8a9SIvan Malov rte_spinlock_unlock(&sfc_mae_switch.lock);
6040fb3e8a9SIvan Malov
6050fb3e8a9SIvan Malov return rc;
6060fb3e8a9SIvan Malov }
6070fb3e8a9SIvan Malov
6080fb3e8a9SIvan Malov int
sfc_mae_switch_port_id_by_entity(uint16_t switch_domain_id,const efx_mport_sel_t * entity_mportp,enum sfc_mae_switch_port_type type,uint16_t * switch_port_id)609599e4e9aSViacheslav Galaktionov sfc_mae_switch_port_id_by_entity(uint16_t switch_domain_id,
610599e4e9aSViacheslav Galaktionov const efx_mport_sel_t *entity_mportp,
611599e4e9aSViacheslav Galaktionov enum sfc_mae_switch_port_type type,
612599e4e9aSViacheslav Galaktionov uint16_t *switch_port_id)
613599e4e9aSViacheslav Galaktionov {
614599e4e9aSViacheslav Galaktionov int rc;
615599e4e9aSViacheslav Galaktionov
616599e4e9aSViacheslav Galaktionov rte_spinlock_lock(&sfc_mae_switch.lock);
617599e4e9aSViacheslav Galaktionov rc = sfc_mae_find_switch_port_id_by_entity(switch_domain_id,
618599e4e9aSViacheslav Galaktionov entity_mportp, type,
619599e4e9aSViacheslav Galaktionov switch_port_id);
620599e4e9aSViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
621599e4e9aSViacheslav Galaktionov
622599e4e9aSViacheslav Galaktionov return rc;
623599e4e9aSViacheslav Galaktionov }
62426706314SViacheslav Galaktionov
62526706314SViacheslav Galaktionov static int
sfc_mae_get_switch_domain_admin_locked(uint16_t switch_domain_id,uint16_t * port_id)62626706314SViacheslav Galaktionov sfc_mae_get_switch_domain_admin_locked(uint16_t switch_domain_id,
62726706314SViacheslav Galaktionov uint16_t *port_id)
62826706314SViacheslav Galaktionov {
62926706314SViacheslav Galaktionov struct sfc_mae_switch_domain *domain;
63026706314SViacheslav Galaktionov
63126706314SViacheslav Galaktionov SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
63226706314SViacheslav Galaktionov
63326706314SViacheslav Galaktionov domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
63426706314SViacheslav Galaktionov if (domain == NULL)
63526706314SViacheslav Galaktionov return EINVAL;
63626706314SViacheslav Galaktionov
63726706314SViacheslav Galaktionov if (domain->mae_admin_port != NULL) {
63826706314SViacheslav Galaktionov *port_id = domain->mae_admin_port->ethdev_port_id;
63926706314SViacheslav Galaktionov return 0;
64026706314SViacheslav Galaktionov }
64126706314SViacheslav Galaktionov
64226706314SViacheslav Galaktionov return ENOENT;
64326706314SViacheslav Galaktionov }
64426706314SViacheslav Galaktionov
64526706314SViacheslav Galaktionov int
sfc_mae_get_switch_domain_admin(uint16_t switch_domain_id,uint16_t * port_id)64626706314SViacheslav Galaktionov sfc_mae_get_switch_domain_admin(uint16_t switch_domain_id,
64726706314SViacheslav Galaktionov uint16_t *port_id)
64826706314SViacheslav Galaktionov {
64926706314SViacheslav Galaktionov int rc;
65026706314SViacheslav Galaktionov
65126706314SViacheslav Galaktionov rte_spinlock_lock(&sfc_mae_switch.lock);
65226706314SViacheslav Galaktionov rc = sfc_mae_get_switch_domain_admin_locked(switch_domain_id, port_id);
65326706314SViacheslav Galaktionov rte_spinlock_unlock(&sfc_mae_switch.lock);
65426706314SViacheslav Galaktionov return rc;
65526706314SViacheslav Galaktionov }
656