drivers: use PCI registration macro
[dpdk.git] / lib / librte_ether / rte_ethdev.c
index e148028..0b9f701 100644 (file)
@@ -58,7 +58,6 @@
 #include <rte_atomic.h>
 #include <rte_branch_prediction.h>
 #include <rte_common.h>
-#include <rte_ring.h>
 #include <rte_mempool.h>
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
@@ -77,6 +76,12 @@ static uint8_t nb_ports;
 /* spinlock for eth device callbacks */
 static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
 
+/* spinlock for add/remove rx callbacks */
+static rte_spinlock_t rte_eth_rx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
+/* spinlock for add/remove tx callbacks */
+static rte_spinlock_t rte_eth_tx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
 /* store statistics names and its offset in stats structure  */
 struct rte_eth_xstats_name_off {
        char name[RTE_ETH_XSTATS_NAME_SIZE];
@@ -239,9 +244,9 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
        return 0;
 }
 
-static int
-rte_eth_dev_init(struct rte_pci_driver *pci_drv,
-                struct rte_pci_device *pci_dev)
+int
+rte_eth_dev_pci_probe(struct rte_pci_driver *pci_drv,
+                     struct rte_pci_device *pci_dev)
 {
        struct eth_driver    *eth_drv;
        struct rte_eth_dev *eth_dev;
@@ -293,8 +298,8 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
        return diag;
 }
 
-static int
-rte_eth_dev_uninit(struct rte_pci_device *pci_dev)
+int
+rte_eth_dev_pci_remove(struct rte_pci_device *pci_dev)
 {
        const struct eth_driver *eth_drv;
        struct rte_eth_dev *eth_dev;
@@ -334,28 +339,6 @@ rte_eth_dev_uninit(struct rte_pci_device *pci_dev)
        return 0;
 }
 
-/**
- * Register an Ethernet [Poll Mode] driver.
- *
- * Function invoked by the initialization function of an Ethernet driver
- * to simultaneously register itself as a PCI driver and as an Ethernet
- * Poll Mode Driver.
- * Invokes the rte_eal_pci_register() function to register the *pci_drv*
- * structure embedded in the *eth_drv* structure, after having stored the
- * address of the rte_eth_dev_init() function in the *devinit* field of
- * the *pci_drv* structure.
- * During the PCI probing phase, the rte_eth_dev_init() function is
- * invoked for each PCI [Ethernet device] matching the embedded PCI
- * identifiers provided by the driver.
- */
-void
-rte_eth_driver_register(struct eth_driver *eth_drv)
-{
-       eth_drv->pci_drv.devinit = rte_eth_dev_init;
-       eth_drv->pci_drv.devuninit = rte_eth_dev_uninit;
-       rte_eal_pci_register(&eth_drv->pci_drv);
-}
-
 int
 rte_eth_dev_is_valid_port(uint8_t port_id)
 {
@@ -400,7 +383,7 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
        return 0;
 }
 
-static int
+int
 rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
 {
        char *tmp;
@@ -419,7 +402,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
        return 0;
 }
 
-static int
+int
 rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
 {
        int i;
@@ -532,7 +515,7 @@ rte_eth_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr)
        if (rte_eal_compare_pci_addr(&vp, &freed_addr) == 0)
                goto err;
 
-       /* invoke devuninit func of the pci driver,
+       /* invoke remove func of the pci driver,
         * also remove the device from pci_device_list */
        if (rte_eal_pci_detach(&freed_addr))
                goto err;
@@ -1484,8 +1467,8 @@ rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
        memset(stats, 0, sizeof(*stats));
 
        RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->stats_get, -ENOTSUP);
-       (*dev->dev_ops->stats_get)(dev, stats);
        stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed;
+       (*dev->dev_ops->stats_get)(dev, stats);
        return 0;
 }
 
@@ -1502,9 +1485,91 @@ rte_eth_stats_reset(uint8_t port_id)
        dev->data->rx_mbuf_alloc_failed = 0;
 }
 
+static int
+get_xstats_count(uint8_t port_id)
+{
+       struct rte_eth_dev *dev;
+       int count;
+
+       RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+       dev = &rte_eth_devices[port_id];
+       if (dev->dev_ops->xstats_get_names != NULL) {
+               count = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0);
+               if (count < 0)
+                       return count;
+       } else
+               count = 0;
+       count += RTE_NB_STATS;
+       count += dev->data->nb_rx_queues * RTE_NB_RXQ_STATS;
+       count += dev->data->nb_tx_queues * RTE_NB_TXQ_STATS;
+       return count;
+}
+
+int
+rte_eth_xstats_get_names(uint8_t port_id,
+       struct rte_eth_xstat_name *xstats_names,
+       unsigned size)
+{
+       struct rte_eth_dev *dev;
+       int cnt_used_entries;
+       int cnt_expected_entries;
+       int cnt_driver_entries;
+       uint32_t idx, id_queue;
+
+       cnt_expected_entries = get_xstats_count(port_id);
+       if (xstats_names == NULL || cnt_expected_entries < 0 ||
+                       (int)size < cnt_expected_entries)
+               return cnt_expected_entries;
+
+       /* port_id checked in get_xstats_count() */
+       dev = &rte_eth_devices[port_id];
+       cnt_used_entries = 0;
+
+       for (idx = 0; idx < RTE_NB_STATS; idx++) {
+               snprintf(xstats_names[cnt_used_entries].name,
+                       sizeof(xstats_names[0].name),
+                       "%s", rte_stats_strings[idx].name);
+               cnt_used_entries++;
+       }
+       for (id_queue = 0; id_queue < dev->data->nb_rx_queues; id_queue++) {
+               for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {
+                       snprintf(xstats_names[cnt_used_entries].name,
+                               sizeof(xstats_names[0].name),
+                               "rx_q%u%s",
+                               id_queue, rte_rxq_stats_strings[idx].name);
+                       cnt_used_entries++;
+               }
+
+       }
+       for (id_queue = 0; id_queue < dev->data->nb_tx_queues; id_queue++) {
+               for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {
+                       snprintf(xstats_names[cnt_used_entries].name,
+                               sizeof(xstats_names[0].name),
+                               "tx_q%u%s",
+                               id_queue, rte_txq_stats_strings[idx].name);
+                       cnt_used_entries++;
+               }
+       }
+
+       if (dev->dev_ops->xstats_get_names != NULL) {
+               /* If there are any driver-specific xstats, append them
+                * to end of list.
+                */
+               cnt_driver_entries = (*dev->dev_ops->xstats_get_names)(
+                       dev,
+                       xstats_names + cnt_used_entries,
+                       size - cnt_used_entries);
+               if (cnt_driver_entries < 0)
+                       return cnt_driver_entries;
+               cnt_used_entries += cnt_driver_entries;
+       }
+
+       return cnt_used_entries;
+}
+
 /* retrieve ethdev extended statistics */
 int
-rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
+rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,
        unsigned n)
 {
        struct rte_eth_stats eth_stats;
@@ -1546,8 +1611,6 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
                stats_ptr = RTE_PTR_ADD(&eth_stats,
                                        rte_stats_strings[i].offset);
                val = *stats_ptr;
-               snprintf(xstats[count].name, sizeof(xstats[count].name),
-                       "%s", rte_stats_strings[i].name);
                xstats[count++].value = val;
        }
 
@@ -1558,9 +1621,6 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
                                        rte_rxq_stats_strings[i].offset +
                                        q * sizeof(uint64_t));
                        val = *stats_ptr;
-                       snprintf(xstats[count].name, sizeof(xstats[count].name),
-                               "rx_q%u_%s", q,
-                               rte_rxq_stats_strings[i].name);
                        xstats[count++].value = val;
                }
        }
@@ -1572,13 +1632,13 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
                                        rte_txq_stats_strings[i].offset +
                                        q * sizeof(uint64_t));
                        val = *stats_ptr;
-                       snprintf(xstats[count].name, sizeof(xstats[count].name),
-                               "tx_q%u_%s", q,
-                               rte_txq_stats_strings[i].name);
                        xstats[count++].value = val;
                }
        }
 
+       for (i = 0; i < count + xcount; i++)
+               xstats[i].id = i;
+
        return count + xcount;
 }
 
@@ -1634,7 +1694,6 @@ rte_eth_dev_set_rx_queue_stats_mapping(uint8_t port_id, uint16_t rx_queue_id,
                        STAT_QMAP_RX);
 }
 
-
 void
 rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
 {
@@ -1656,6 +1715,8 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
        (*dev->dev_ops->dev_infos_get)(dev, dev_info);
        dev_info->pci_dev = dev->pci_dev;
        dev_info->driver_name = dev->data->drv_name;
+       dev_info->nb_rx_queues = dev->data->nb_rx_queues;
+       dev_info->nb_tx_queues = dev->data->nb_tx_queues;
 }
 
 int
@@ -2905,7 +2966,6 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
                rte_errno = EINVAL;
                return NULL;
        }
-
        struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
 
        if (cb == NULL) {
@@ -2916,6 +2976,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
        cb->fn.rx = fn;
        cb->param = user_param;
 
+       rte_spinlock_lock(&rte_eth_rx_cb_lock);
        /* Add the callbacks in fifo order. */
        struct rte_eth_rxtx_callback *tail =
                rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
@@ -2928,6 +2989,42 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
                        tail = tail->next;
                tail->next = cb;
        }
+       rte_spinlock_unlock(&rte_eth_rx_cb_lock);
+
+       return cb;
+}
+
+void *
+rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+               rte_rx_callback_fn fn, void *user_param)
+{
+#ifndef RTE_ETHDEV_RXTX_CALLBACKS
+       rte_errno = ENOTSUP;
+       return NULL;
+#endif
+       /* check input parameters */
+       if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL ||
+               queue_id >= rte_eth_devices[port_id].data->nb_rx_queues) {
+               rte_errno = EINVAL;
+               return NULL;
+       }
+
+       struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
+
+       if (cb == NULL) {
+               rte_errno = ENOMEM;
+               return NULL;
+       }
+
+       cb->fn.rx = fn;
+       cb->param = user_param;
+
+       rte_spinlock_lock(&rte_eth_rx_cb_lock);
+       /* Add the callbacks at fisrt position*/
+       cb->next = rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
+       rte_smp_wmb();
+       rte_eth_devices[port_id].post_rx_burst_cbs[queue_id] = cb;
+       rte_spinlock_unlock(&rte_eth_rx_cb_lock);
 
        return cb;
 }
@@ -2957,6 +3054,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
        cb->fn.tx = fn;
        cb->param = user_param;
 
+       rte_spinlock_lock(&rte_eth_tx_cb_lock);
        /* Add the callbacks in fifo order. */
        struct rte_eth_rxtx_callback *tail =
                rte_eth_devices[port_id].pre_tx_burst_cbs[queue_id];
@@ -2969,6 +3067,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
                        tail = tail->next;
                tail->next = cb;
        }
+       rte_spinlock_unlock(&rte_eth_tx_cb_lock);
 
        return cb;
 }
@@ -2987,29 +3086,24 @@ rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
                return -EINVAL;
 
        struct rte_eth_dev *dev = &rte_eth_devices[port_id];
-       struct rte_eth_rxtx_callback *cb = dev->post_rx_burst_cbs[queue_id];
-       struct rte_eth_rxtx_callback *prev_cb;
-
-       /* Reset head pointer and remove user cb if first in the list. */
-       if (cb == user_cb) {
-               dev->post_rx_burst_cbs[queue_id] = user_cb->next;
-               return 0;
-       }
-
-       /* Remove the user cb from the callback list. */
-       do {
-               prev_cb = cb;
-               cb = cb->next;
-
+       struct rte_eth_rxtx_callback *cb;
+       struct rte_eth_rxtx_callback **prev_cb;
+       int ret = -EINVAL;
+
+       rte_spinlock_lock(&rte_eth_rx_cb_lock);
+       prev_cb = &dev->post_rx_burst_cbs[queue_id];
+       for (; *prev_cb != NULL; prev_cb = &cb->next) {
+               cb = *prev_cb;
                if (cb == user_cb) {
-                       prev_cb->next = user_cb->next;
-                       return 0;
+                       /* Remove the user cb from the callback list. */
+                       *prev_cb = cb->next;
+                       ret = 0;
+                       break;
                }
+       }
+       rte_spinlock_unlock(&rte_eth_rx_cb_lock);
 
-       } while (cb != NULL);
-
-       /* Callback wasn't found. */
-       return -EINVAL;
+       return ret;
 }
 
 int
@@ -3026,29 +3120,24 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
                return -EINVAL;
 
        struct rte_eth_dev *dev = &rte_eth_devices[port_id];
-       struct rte_eth_rxtx_callback *cb = dev->pre_tx_burst_cbs[queue_id];
-       struct rte_eth_rxtx_callback *prev_cb;
-
-       /* Reset head pointer and remove user cb if first in the list. */
-       if (cb == user_cb) {
-               dev->pre_tx_burst_cbs[queue_id] = user_cb->next;
-               return 0;
-       }
-
-       /* Remove the user cb from the callback list. */
-       do {
-               prev_cb = cb;
-               cb = cb->next;
-
+       int ret = -EINVAL;
+       struct rte_eth_rxtx_callback *cb;
+       struct rte_eth_rxtx_callback **prev_cb;
+
+       rte_spinlock_lock(&rte_eth_tx_cb_lock);
+       prev_cb = &dev->pre_tx_burst_cbs[queue_id];
+       for (; *prev_cb != NULL; prev_cb = &cb->next) {
+               cb = *prev_cb;
                if (cb == user_cb) {
-                       prev_cb->next = user_cb->next;
-                       return 0;
+                       /* Remove the user cb from the callback list. */
+                       *prev_cb = cb->next;
+                       ret = 0;
+                       break;
                }
+       }
+       rte_spinlock_unlock(&rte_eth_tx_cb_lock);
 
-       } while (cb != NULL);
-
-       /* Callback wasn't found. */
-       return -EINVAL;
+       return ret;
 }
 
 int
@@ -3198,18 +3287,6 @@ rte_eth_timesync_write_time(uint8_t port_id, const struct timespec *timestamp)
        return (*dev->dev_ops->timesync_write_time)(dev, timestamp);
 }
 
-int
-rte_eth_dev_get_reg_length(uint8_t port_id)
-{
-       struct rte_eth_dev *dev;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
-
-       dev = &rte_eth_devices[port_id];
-       RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
-       return (*dev->dev_ops->get_reg_length)(dev);
-}
-
 int
 rte_eth_dev_get_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
 {