+static int
+sfc_parse_rte_devargs(const char *args, struct rte_eth_devargs *devargs)
+{
+ struct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };
+ int rc;
+
+ if (args != NULL) {
+ rc = rte_eth_devargs_parse(args, ð_da);
+ if (rc != 0) {
+ SFC_GENERIC_LOG(ERR,
+ "Failed to parse generic devargs '%s'",
+ args);
+ return rc;
+ }
+ }
+
+ *devargs = eth_da;
+
+ return 0;
+}
+
+static int
+sfc_eth_dev_find_or_create(struct rte_pci_device *pci_dev,
+ struct sfc_ethdev_init_data *init_data,
+ struct rte_eth_dev **devp,
+ bool *dev_created)
+{
+ struct rte_eth_dev *dev;
+ bool created = false;
+ int rc;
+
+ dev = rte_eth_dev_allocated(pci_dev->device.name);
+ if (dev == NULL) {
+ rc = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name,
+ sizeof(struct sfc_adapter_shared),
+ eth_dev_pci_specific_init, pci_dev,
+ sfc_eth_dev_init, init_data);
+ if (rc != 0) {
+ SFC_GENERIC_LOG(ERR, "Failed to create sfc ethdev '%s'",
+ pci_dev->device.name);
+ return rc;
+ }
+
+ created = true;
+
+ dev = rte_eth_dev_allocated(pci_dev->device.name);
+ if (dev == NULL) {
+ SFC_GENERIC_LOG(ERR,
+ "Failed to find allocated sfc ethdev '%s'",
+ pci_dev->device.name);
+ return -ENODEV;
+ }
+ }
+
+ *devp = dev;
+ *dev_created = created;
+
+ return 0;
+}
+
+static int
+sfc_eth_dev_create_repr(struct sfc_adapter *sa,
+ efx_pcie_interface_t controller,
+ uint16_t port,
+ uint16_t repr_port,
+ enum rte_eth_representor_type type)
+{
+ struct sfc_repr_entity_info entity;
+ efx_mport_sel_t mport_sel;
+ int rc;
+
+ switch (type) {
+ case RTE_ETH_REPRESENTOR_NONE:
+ return 0;
+ case RTE_ETH_REPRESENTOR_VF:
+ case RTE_ETH_REPRESENTOR_PF:
+ break;
+ case RTE_ETH_REPRESENTOR_SF:
+ sfc_err(sa, "SF representors are not supported");
+ return ENOTSUP;
+ default:
+ sfc_err(sa, "unknown representor type: %d", type);
+ return ENOTSUP;
+ }
+
+ rc = efx_mae_mport_by_pcie_mh_function(controller,
+ port,
+ repr_port,
+ &mport_sel);
+ if (rc != 0) {
+ sfc_err(sa,
+ "failed to get m-port selector for controller %u port %u repr_port %u: %s",
+ controller, port, repr_port, rte_strerror(-rc));
+ return rc;
+ }
+
+ memset(&entity, 0, sizeof(entity));
+ entity.type = type;
+ entity.intf = controller;
+ entity.pf = port;
+ entity.vf = repr_port;
+
+ rc = sfc_repr_create(sa->eth_dev, &entity, sa->mae.switch_domain_id,
+ &mport_sel);
+ if (rc != 0) {
+ sfc_err(sa,
+ "failed to create representor for controller %u port %u repr_port %u: %s",
+ controller, port, repr_port, rte_strerror(-rc));
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+sfc_eth_dev_create_repr_port(struct sfc_adapter *sa,
+ const struct rte_eth_devargs *eth_da,
+ efx_pcie_interface_t controller,
+ uint16_t port)
+{
+ int first_error = 0;
+ uint16_t i;
+ int rc;
+
+ if (eth_da->type == RTE_ETH_REPRESENTOR_PF) {
+ return sfc_eth_dev_create_repr(sa, controller, port,
+ EFX_PCI_VF_INVALID,
+ eth_da->type);
+ }
+
+ for (i = 0; i < eth_da->nb_representor_ports; i++) {
+ rc = sfc_eth_dev_create_repr(sa, controller, port,
+ eth_da->representor_ports[i],
+ eth_da->type);
+ if (rc != 0 && first_error == 0)
+ first_error = rc;
+ }
+
+ return first_error;
+}
+
+static int
+sfc_eth_dev_create_repr_controller(struct sfc_adapter *sa,
+ const struct rte_eth_devargs *eth_da,
+ efx_pcie_interface_t controller)
+{
+ const efx_nic_cfg_t *encp;
+ int first_error = 0;
+ uint16_t default_port;
+ uint16_t i;
+ int rc;
+
+ if (eth_da->nb_ports == 0) {
+ encp = efx_nic_cfg_get(sa->nic);
+ default_port = encp->enc_intf == controller ? encp->enc_pf : 0;
+ return sfc_eth_dev_create_repr_port(sa, eth_da, controller,
+ default_port);
+ }
+
+ for (i = 0; i < eth_da->nb_ports; i++) {
+ rc = sfc_eth_dev_create_repr_port(sa, eth_da, controller,
+ eth_da->ports[i]);
+ if (rc != 0 && first_error == 0)
+ first_error = rc;
+ }
+
+ return first_error;
+}
+
+static int
+sfc_eth_dev_create_representors(struct rte_eth_dev *dev,
+ const struct rte_eth_devargs *eth_da)
+{
+ efx_pcie_interface_t intf;
+ const efx_nic_cfg_t *encp;
+ struct sfc_adapter *sa;
+ uint16_t switch_domain_id;
+ uint16_t i;
+ int rc;
+
+ sa = sfc_adapter_by_eth_dev(dev);
+ switch_domain_id = sa->mae.switch_domain_id;
+
+ switch (eth_da->type) {
+ case RTE_ETH_REPRESENTOR_NONE:
+ return 0;
+ case RTE_ETH_REPRESENTOR_PF:
+ case RTE_ETH_REPRESENTOR_VF:
+ break;
+ case RTE_ETH_REPRESENTOR_SF:
+ sfc_err(sa, "SF representors are not supported");
+ return -ENOTSUP;
+ default:
+ sfc_err(sa, "unknown representor type: %d",
+ eth_da->type);
+ return -ENOTSUP;
+ }
+
+ if (!sa->switchdev) {
+ sfc_err(sa, "cannot create representors in non-switchdev mode");
+ return -EINVAL;
+ }
+
+ if (!sfc_repr_available(sfc_sa2shared(sa))) {
+ sfc_err(sa, "cannot create representors: unsupported");
+
+ return -ENOTSUP;
+ }
+
+ /*
+ * This is needed to construct the DPDK controller -> EFX interface
+ * mapping.
+ */
+ sfc_adapter_lock(sa);
+ rc = sfc_process_mport_journal(sa);
+ sfc_adapter_unlock(sa);
+ if (rc != 0) {
+ SFC_ASSERT(rc > 0);
+ return -rc;
+ }
+
+ if (eth_da->nb_mh_controllers > 0) {
+ for (i = 0; i < eth_da->nb_mh_controllers; i++) {
+ rc = sfc_mae_switch_domain_get_intf(switch_domain_id,
+ eth_da->mh_controllers[i],
+ &intf);
+ if (rc != 0) {
+ sfc_err(sa, "failed to get representor");
+ continue;
+ }
+ sfc_eth_dev_create_repr_controller(sa, eth_da, intf);
+ }
+ } else {
+ encp = efx_nic_cfg_get(sa->nic);
+ sfc_eth_dev_create_repr_controller(sa, eth_da, encp->enc_intf);
+ }
+
+ return 0;
+}
+
+static int sfc_eth_dev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+ struct rte_pci_device *pci_dev)
+{
+ struct sfc_ethdev_init_data init_data;
+ struct rte_eth_devargs eth_da;
+ struct rte_eth_dev *dev;
+ bool dev_created;
+ int rc;
+
+ if (pci_dev->device.devargs != NULL) {
+ rc = sfc_parse_rte_devargs(pci_dev->device.devargs->args,
+ ð_da);
+ if (rc != 0)
+ return rc;
+ } else {
+ memset(ð_da, 0, sizeof(eth_da));
+ }
+
+ /* If no VF representors specified, check for PF ones */
+ if (eth_da.nb_representor_ports > 0)
+ init_data.nb_representors = eth_da.nb_representor_ports;
+ else
+ init_data.nb_representors = eth_da.nb_ports;
+
+ if (init_data.nb_representors > 0 &&
+ rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ SFC_GENERIC_LOG(ERR,
+ "Create representors from secondary process not supported, dev '%s'",
+ pci_dev->device.name);
+ return -ENOTSUP;
+ }
+
+ /*
+ * Driver supports RTE_PCI_DRV_PROBE_AGAIN. Hence create device only
+ * if it does not already exist. Re-probing an existing device is
+ * expected to allow additional representors to be configured.
+ */
+ rc = sfc_eth_dev_find_or_create(pci_dev, &init_data, &dev,
+ &dev_created);
+ if (rc != 0)
+ return rc;
+
+ rc = sfc_eth_dev_create_representors(dev, ð_da);
+ if (rc != 0) {
+ if (dev_created)
+ (void)rte_eth_dev_destroy(dev, sfc_eth_dev_uninit);
+
+ return rc;
+ }
+
+ return 0;
+}
+
+static int sfc_eth_dev_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, sfc_eth_dev_uninit);
+}
+
+static struct rte_pci_driver sfc_efx_pmd = {
+ .id_table = pci_id_sfc_efx_map,
+ .drv_flags =
+ RTE_PCI_DRV_INTR_LSC |
+ RTE_PCI_DRV_NEED_MAPPING |
+ RTE_PCI_DRV_PROBE_AGAIN,
+ .probe = sfc_eth_dev_pci_probe,
+ .remove = sfc_eth_dev_pci_remove,