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 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 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 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 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 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 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 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