xref: /dpdk/drivers/net/sfc/sfc_switch.c (revision ef96f7eb4cce942d5a10de0c8ceab21ebe7d17c3)
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 *
sfc_mae_find_switch_domain_by_id(uint16_t switch_domain_id)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
sfc_mae_switch_ports_iterate(uint16_t switch_domain_id,sfc_mae_switch_port_iterator_cb * cb,void * data)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 *
sfc_mae_find_switch_domain_by_hw_switch_id(const struct sfc_hw_switch_id * id)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
sfc_mae_assign_switch_domain(struct sfc_adapter * sa,uint16_t * switch_domain_id)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
sfc_mae_switch_domain_controllers(uint16_t switch_domain_id,const efx_pcie_interface_t ** controllers,size_t * nb_controllers)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
sfc_mae_switch_domain_map_controllers(uint16_t switch_domain_id,efx_pcie_interface_t * controllers,size_t nb_controllers)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
sfc_mae_switch_controller_from_mapping(const efx_pcie_interface_t * controllers,size_t nb_controllers,efx_pcie_interface_t intf,int * controller)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
sfc_mae_switch_domain_get_controller(uint16_t switch_domain_id,efx_pcie_interface_t intf,int * controller)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 
sfc_mae_switch_domain_get_intf(uint16_t switch_domain_id,int controller,efx_pcie_interface_t * intf)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 *
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)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
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)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
sfc_mae_assign_switch_port(uint16_t switch_domain_id,const struct sfc_mae_switch_port_request * req,uint16_t * switch_port_id)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
sfc_mae_clear_switch_port(uint16_t switch_domain_id,uint16_t switch_port_id)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 	struct sfc_mae_switch_port *port;
493 
494 	rte_spinlock_lock(&sfc_mae_switch.lock);
495 
496 	domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
497 	if (domain == NULL) {
498 		rte_spinlock_unlock(&sfc_mae_switch.lock);
499 		return EINVAL;
500 	}
501 
502 	if (domain->mae_admin_port != NULL &&
503 	    domain->mae_admin_port->id == switch_port_id) {
504 		domain->mae_admin_port->data.indep.mae_admin = B_FALSE;
505 		domain->mae_admin_port = NULL;
506 	}
507 
508 	TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
509 		if (port->id == switch_port_id) {
510 			/*
511 			 * Invalidate the field to prevent wrong
512 			 * look-ups from flow rule handling path.
513 			 */
514 			port->ethdev_port_id = RTE_MAX_ETHPORTS;
515 			break;
516 		}
517 	}
518 
519 	rte_spinlock_unlock(&sfc_mae_switch.lock);
520 	return 0;
521 }
522 
523 /* This function expects to be called only when the lock is held */
524 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)525 sfc_mae_find_switch_port_by_ethdev(uint16_t switch_domain_id,
526 				   uint16_t ethdev_port_id,
527 				   struct sfc_mae_switch_port **switch_port)
528 {
529 	struct sfc_mae_switch_domain *domain;
530 	struct sfc_mae_switch_port *port;
531 
532 	SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
533 
534 	if (ethdev_port_id == RTE_MAX_ETHPORTS)
535 		return EINVAL;
536 
537 	domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
538 	if (domain == NULL)
539 		return EINVAL;
540 
541 	TAILQ_FOREACH(port, &domain->ports, switch_domain_ports) {
542 		if (port->ethdev_port_id == ethdev_port_id) {
543 			*switch_port = port;
544 			return 0;
545 		}
546 	}
547 
548 	return ENOENT;
549 }
550 
551 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)552 sfc_mae_switch_get_ethdev_mport(uint16_t switch_domain_id,
553 				uint16_t ethdev_port_id,
554 				unsigned int allowed_mae_switch_port_types,
555 				efx_mport_sel_t *mport_sel)
556 {
557 	struct sfc_mae_switch_port *port;
558 	int rc;
559 
560 	rte_spinlock_lock(&sfc_mae_switch.lock);
561 	rc = sfc_mae_find_switch_port_by_ethdev(switch_domain_id,
562 						ethdev_port_id, &port);
563 	if (rc != 0)
564 		goto unlock;
565 
566 	if (((1U << port->type) & allowed_mae_switch_port_types) == 0) {
567 		rc = ENOTSUP;
568 		goto unlock;
569 	}
570 
571 	*mport_sel = port->ethdev_mport;
572 
573 unlock:
574 	rte_spinlock_unlock(&sfc_mae_switch.lock);
575 
576 	return rc;
577 }
578 
579 int
sfc_mae_switch_get_entity_mport(uint16_t switch_domain_id,uint16_t ethdev_port_id,efx_mport_sel_t * mport_sel)580 sfc_mae_switch_get_entity_mport(uint16_t switch_domain_id,
581 				uint16_t ethdev_port_id,
582 				efx_mport_sel_t *mport_sel)
583 {
584 	static struct sfc_mae_switch_port *port;
585 	int rc;
586 
587 	rte_spinlock_lock(&sfc_mae_switch.lock);
588 	rc = sfc_mae_find_switch_port_by_ethdev(switch_domain_id,
589 						ethdev_port_id, &port);
590 	if (rc != 0)
591 		goto unlock;
592 
593 	if (port->type == SFC_MAE_SWITCH_PORT_INDEPENDENT &&
594 	    !port->data.indep.mae_admin) {
595 		/* See sfc_mae_assign_entity_mport() */
596 		rc = ENOTSUP;
597 		goto unlock;
598 	}
599 
600 	*mport_sel = port->entity_mport;
601 
602 unlock:
603 	rte_spinlock_unlock(&sfc_mae_switch.lock);
604 
605 	return rc;
606 }
607 
608 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)609 sfc_mae_switch_port_id_by_entity(uint16_t switch_domain_id,
610 				 const efx_mport_sel_t *entity_mportp,
611 				 enum sfc_mae_switch_port_type type,
612 				 uint16_t *switch_port_id)
613 {
614 	int rc;
615 
616 	rte_spinlock_lock(&sfc_mae_switch.lock);
617 	rc = sfc_mae_find_switch_port_id_by_entity(switch_domain_id,
618 						   entity_mportp, type,
619 						   switch_port_id);
620 	rte_spinlock_unlock(&sfc_mae_switch.lock);
621 
622 	return rc;
623 }
624 
625 static int
sfc_mae_get_switch_domain_admin_locked(uint16_t switch_domain_id,uint16_t * port_id)626 sfc_mae_get_switch_domain_admin_locked(uint16_t switch_domain_id,
627 				       uint16_t *port_id)
628 {
629 	struct sfc_mae_switch_domain *domain;
630 
631 	SFC_ASSERT(rte_spinlock_is_locked(&sfc_mae_switch.lock));
632 
633 	domain = sfc_mae_find_switch_domain_by_id(switch_domain_id);
634 	if (domain == NULL)
635 		return EINVAL;
636 
637 	if (domain->mae_admin_port != NULL) {
638 		*port_id = domain->mae_admin_port->ethdev_port_id;
639 		return 0;
640 	}
641 
642 	return ENOENT;
643 }
644 
645 int
sfc_mae_get_switch_domain_admin(uint16_t switch_domain_id,uint16_t * port_id)646 sfc_mae_get_switch_domain_admin(uint16_t switch_domain_id,
647 				uint16_t *port_id)
648 {
649 	int rc;
650 
651 	rte_spinlock_lock(&sfc_mae_switch.lock);
652 	rc = sfc_mae_get_switch_domain_admin_locked(switch_domain_id, port_id);
653 	rte_spinlock_unlock(&sfc_mae_switch.lock);
654 	return rc;
655 }
656