ethdev: fix invalid configuration after failure
[dpdk.git] / lib / librte_ethdev / rte_ethdev.c
index 0a4cad5..04dff1f 100644 (file)
@@ -187,7 +187,7 @@ enum {
        STAT_QMAP_RX
 };
 
-int __rte_experimental
+int
 rte_eth_iterator_init(struct rte_dev_iterator *iter, const char *devargs_str)
 {
        int ret;
@@ -288,7 +288,7 @@ error:
        return ret;
 }
 
-uint16_t __rte_experimental
+uint16_t
 rte_eth_iterator_next(struct rte_dev_iterator *iter)
 {
        if (iter->cls == NULL) /* invalid ethdev iterator */
@@ -317,7 +317,7 @@ rte_eth_iterator_next(struct rte_dev_iterator *iter)
        return RTE_MAX_ETHPORTS;
 }
 
-void __rte_experimental
+void
 rte_eth_iterator_cleanup(struct rte_dev_iterator *iter)
 {
        if (iter->bus_str == NULL)
@@ -513,7 +513,9 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
 
        rte_eth_dev_shared_data_prepare();
 
-       _rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_DESTROY, NULL);
+       if (eth_dev->state != RTE_ETH_DEV_UNUSED)
+               _rte_eth_dev_callback_process(eth_dev,
+                               RTE_ETH_EVENT_DESTROY, NULL);
 
        rte_spinlock_lock(&rte_eth_dev_shared_data->ownership_lock);
 
@@ -801,87 +803,6 @@ eth_err(uint16_t port_id, int ret)
        return ret;
 }
 
-/* attach the new device, then store port_id of the device */
-int
-rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
-{
-       int current = rte_eth_dev_count_total();
-       struct rte_devargs da;
-       int ret = -1;
-
-       memset(&da, 0, sizeof(da));
-
-       if ((devargs == NULL) || (port_id == NULL)) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       /* parse devargs */
-       if (rte_devargs_parse(&da, devargs))
-               goto err;
-
-       ret = rte_eal_hotplug_add(da.bus->name, da.name, da.args);
-       if (ret < 0)
-               goto err;
-
-       /* no point looking at the port count if no port exists */
-       if (!rte_eth_dev_count_total()) {
-               RTE_ETHDEV_LOG(ERR, "No port found for device (%s)\n", da.name);
-               ret = -1;
-               goto err;
-       }
-
-       /* if nothing happened, there is a bug here, since some driver told us
-        * it did attach a device, but did not create a port.
-        * FIXME: race condition in case of plug-out of another device
-        */
-       if (current == rte_eth_dev_count_total()) {
-               ret = -1;
-               goto err;
-       }
-
-       *port_id = eth_dev_last_created_port;
-       ret = 0;
-
-err:
-       free(da.args);
-       return ret;
-}
-
-/* detach the device, then store the name of the device */
-int
-rte_eth_dev_detach(uint16_t port_id, char *name __rte_unused)
-{
-       struct rte_device *dev;
-       struct rte_bus *bus;
-       uint32_t dev_flags;
-       int ret = -1;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
-
-       dev_flags = rte_eth_devices[port_id].data->dev_flags;
-       if (dev_flags & RTE_ETH_DEV_BONDED_SLAVE) {
-               RTE_ETHDEV_LOG(ERR,
-                       "Port %"PRIu16" is bonded, cannot detach\n", port_id);
-               return -ENOTSUP;
-       }
-
-       dev = rte_eth_devices[port_id].device;
-       if (dev == NULL)
-               return -EINVAL;
-
-       bus = rte_bus_find_by_device(dev);
-       if (bus == NULL)
-               return -ENOENT;
-
-       ret = rte_eal_hotplug_remove(bus->name, dev->name);
-       if (ret < 0)
-               return ret;
-
-       rte_eth_dev_release_port(&rte_eth_devices[port_id]);
-       return 0;
-}
-
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
@@ -1133,7 +1054,7 @@ rte_eth_speed_bitflag(uint32_t speed, int duplex)
        }
 }
 
-const char * __rte_experimental
+const char *
 rte_eth_dev_rx_offload_name(uint64_t offload)
 {
        const char *name = "UNKNOWN";
@@ -1149,7 +1070,7 @@ rte_eth_dev_rx_offload_name(uint64_t offload)
        return name;
 }
 
-const char * __rte_experimental
+const char *
 rte_eth_dev_tx_offload_name(uint64_t offload)
 {
        const char *name = "UNKNOWN";
@@ -1171,8 +1092,10 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
 {
        struct rte_eth_dev *dev;
        struct rte_eth_dev_info dev_info;
+       struct rte_eth_conf orig_conf;
        struct rte_eth_conf local_conf = *dev_conf;
        int diag;
+       int ret;
 
        RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
 
@@ -1219,6 +1142,9 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                return -EBUSY;
        }
 
+        /* Store original config, as rollback required on failure */
+       memcpy(&orig_conf, &dev->data->dev_conf, sizeof(dev->data->dev_conf));
+
        /* Copy the dev_conf parameter into the dev structure */
        memcpy(&dev->data->dev_conf, &local_conf, sizeof(dev->data->dev_conf));
 
@@ -1230,13 +1156,15 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
        if (nb_rx_q > dev_info.max_rx_queues) {
                RTE_ETHDEV_LOG(ERR, "Ethdev port_id=%u nb_rx_queues=%u > %u\n",
                        port_id, nb_rx_q, dev_info.max_rx_queues);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto rollback;
        }
 
        if (nb_tx_q > dev_info.max_tx_queues) {
                RTE_ETHDEV_LOG(ERR, "Ethdev port_id=%u nb_tx_queues=%u > %u\n",
                        port_id, nb_tx_q, dev_info.max_tx_queues);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto rollback;
        }
 
        /* Check that the device supports requested interrupts */
@@ -1244,13 +1172,15 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                        (!(dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC))) {
                RTE_ETHDEV_LOG(ERR, "Driver %s does not support lsc\n",
                        dev->device->driver->name);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto rollback;
        }
        if ((dev_conf->intr_conf.rmv == 1) &&
                        (!(dev->data->dev_flags & RTE_ETH_DEV_INTR_RMV))) {
                RTE_ETHDEV_LOG(ERR, "Driver %s does not support rmv\n",
                        dev->device->driver->name);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto rollback;
        }
 
        /*
@@ -1263,13 +1193,15 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                                "Ethdev port_id=%u max_rx_pkt_len %u > max valid value %u\n",
                                port_id, dev_conf->rxmode.max_rx_pkt_len,
                                dev_info.max_rx_pktlen);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto rollback;
                } else if (dev_conf->rxmode.max_rx_pkt_len < ETHER_MIN_LEN) {
                        RTE_ETHDEV_LOG(ERR,
                                "Ethdev port_id=%u max_rx_pkt_len %u < min valid value %u\n",
                                port_id, dev_conf->rxmode.max_rx_pkt_len,
                                (unsigned)ETHER_MIN_LEN);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto rollback;
                }
        } else {
                if (dev_conf->rxmode.max_rx_pkt_len < ETHER_MIN_LEN ||
@@ -1288,7 +1220,8 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                        port_id, local_conf.rxmode.offloads,
                        dev_info.rx_offload_capa,
                        __func__);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto rollback;
        }
        if ((local_conf.txmode.offloads & dev_info.tx_offload_capa) !=
             local_conf.txmode.offloads) {
@@ -1298,7 +1231,8 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                        port_id, local_conf.txmode.offloads,
                        dev_info.tx_offload_capa,
                        __func__);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto rollback;
        }
 
        /* Check that device supports requested rss hash functions. */
@@ -1309,7 +1243,8 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                        "Ethdev port_id=%u invalid rss_hf: 0x%"PRIx64", valid value: 0x%"PRIx64"\n",
                        port_id, dev_conf->rx_adv_conf.rss_conf.rss_hf,
                        dev_info.flow_type_rss_offloads);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto rollback;
        }
 
        /*
@@ -1320,7 +1255,8 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                RTE_ETHDEV_LOG(ERR,
                        "Port%u rte_eth_dev_rx_queue_config = %d\n",
                        port_id, diag);
-               return diag;
+               ret = diag;
+               goto rollback;
        }
 
        diag = rte_eth_dev_tx_queue_config(dev, nb_tx_q);
@@ -1329,7 +1265,8 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                        "Port%u rte_eth_dev_tx_queue_config = %d\n",
                        port_id, diag);
                rte_eth_dev_rx_queue_config(dev, 0);
-               return diag;
+               ret = diag;
+               goto rollback;
        }
 
        diag = (*dev->dev_ops->dev_configure)(dev);
@@ -1338,7 +1275,8 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                        port_id, diag);
                rte_eth_dev_rx_queue_config(dev, 0);
                rte_eth_dev_tx_queue_config(dev, 0);
-               return eth_err(port_id, diag);
+               ret = eth_err(port_id, diag);
+               goto rollback;
        }
 
        /* Initialize Rx profiling if enabled at compilation time. */
@@ -1348,10 +1286,16 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
                        port_id, diag);
                rte_eth_dev_rx_queue_config(dev, 0);
                rte_eth_dev_tx_queue_config(dev, 0);
-               return eth_err(port_id, diag);
+               ret = eth_err(port_id, diag);
+               goto rollback;
        }
 
        return 0;
+
+rollback:
+       memcpy(&dev->data->dev_conf, &orig_conf, sizeof(dev->data->dev_conf));
+
+       return ret;
 }
 
 void
@@ -3726,11 +3670,10 @@ rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
                return -ENODEV;
 
        RTE_FUNC_PTR_OR_ERR_RET(*ethdev_uninit, -EINVAL);
-       if (ethdev_uninit) {
-               ret = ethdev_uninit(ethdev);
-               if (ret)
-                       return ret;
-       }
+
+       ret = ethdev_uninit(ethdev);
+       if (ret)
+               return ret;
 
        return rte_eth_dev_release_port(ethdev);
 }
@@ -4390,7 +4333,7 @@ enum rte_eth_switch_domain_state {
  * RTE_MAX_ETHPORTS elements as there cannot be more active switch domains than
  * ethdev ports in a single process.
  */
-struct rte_eth_dev_switch {
+static struct rte_eth_dev_switch {
        enum rte_eth_switch_domain_state state;
 } rte_eth_switch_domains[RTE_MAX_ETHPORTS];
 
@@ -4431,8 +4374,6 @@ rte_eth_switch_domain_free(uint16_t domain_id)
        return 0;
 }
 
-typedef int (*rte_eth_devargs_callback_t)(char *str, void *data);
-
 static int
 rte_eth_devargs_tokenise(struct rte_kvargs *arglist, const char *str_in)
 {
@@ -4497,89 +4438,6 @@ rte_eth_devargs_tokenise(struct rte_kvargs *arglist, const char *str_in)
        }
 }
 
-static int
-rte_eth_devargs_parse_list(char *str, rte_eth_devargs_callback_t callback,
-       void *data)
-{
-       char *str_start;
-       int state;
-       int result;
-
-       if (*str != '[')
-               /* Single element, not a list */
-               return callback(str, data);
-
-       /* Sanity check, then strip the brackets */
-       str_start = &str[strlen(str) - 1];
-       if (*str_start != ']') {
-               RTE_LOG(ERR, EAL, "(%s): List does not end with ']'", str);
-               return -EINVAL;
-       }
-       str++;
-       *str_start = '\0';
-
-       /* Process list elements */
-       state = 0;
-       while (1) {
-               if (state == 0) {
-                       if (*str == '\0')
-                               break;
-                       if (*str != ',') {
-                               str_start = str;
-                               state = 1;
-                       }
-               } else if (state == 1) {
-                       if (*str == ',' || *str == '\0') {
-                               if (str > str_start) {
-                                       /* Non-empty string fragment */
-                                       *str = '\0';
-                                       result = callback(str_start, data);
-                                       if (result < 0)
-                                               return result;
-                               }
-                               state = 0;
-                       }
-               }
-               str++;
-       }
-       return 0;
-}
-
-static int
-rte_eth_devargs_process_range(char *str, uint16_t *list, uint16_t *len_list,
-       const uint16_t max_list)
-{
-       uint16_t lo, hi, val;
-       int result;
-
-       result = sscanf(str, "%hu-%hu", &lo, &hi);
-       if (result == 1) {
-               if (*len_list >= max_list)
-                       return -ENOMEM;
-               list[(*len_list)++] = lo;
-       } else if (result == 2) {
-               if (lo >= hi || lo > RTE_MAX_ETHPORTS || hi > RTE_MAX_ETHPORTS)
-                       return -EINVAL;
-               for (val = lo; val <= hi; val++) {
-                       if (*len_list >= max_list)
-                               return -ENOMEM;
-                       list[(*len_list)++] = val;
-               }
-       } else
-               return -EINVAL;
-       return 0;
-}
-
-
-static int
-rte_eth_devargs_parse_representor_ports(char *str, void *data)
-{
-       struct rte_eth_devargs *eth_da = data;
-
-       return rte_eth_devargs_process_range(str, eth_da->representor_ports,
-               &eth_da->nb_representor_ports, RTE_MAX_ETHPORTS);
-}
-
 int __rte_experimental
 rte_eth_devargs_parse(const char *dargs, struct rte_eth_devargs *eth_da)
 {