+ return count;
+}
+
+/* retrieve ethdev extended statistics */
+int
+rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
+ uint64_t *values, unsigned int size)
+{
+ unsigned int no_basic_stat_requested = 1;
+ unsigned int no_ext_stat_requested = 1;
+ unsigned int num_xstats_filled;
+ unsigned int basic_count;
+ uint16_t expected_entries;
+ struct rte_eth_dev *dev;
+ unsigned int i;
+ int ret;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ ret = get_xstats_count(port_id);
+ if (ret < 0)
+ return ret;
+ expected_entries = (uint16_t)ret;
+ struct rte_eth_xstat xstats[expected_entries];
+ dev = &rte_eth_devices[port_id];
+ basic_count = get_xstats_basic_count(dev);
+
+ /* Return max number of stats if no ids given */
+ if (!ids) {
+ if (!values)
+ return expected_entries;
+ else if (values && size < expected_entries)
+ return expected_entries;
+ }
+
+ if (ids && !values)
+ return -EINVAL;
+
+ if (ids && dev->dev_ops->xstats_get_by_id != NULL && size) {
+ unsigned int basic_count = get_xstats_basic_count(dev);
+ uint64_t ids_copy[size];
+
+ for (i = 0; i < size; i++) {
+ if (ids[i] < basic_count) {
+ no_basic_stat_requested = 0;
+ break;
+ }
+
+ /*
+ * Convert ids to xstats ids that PMD knows.
+ * ids known by user are basic + extended stats.
+ */
+ ids_copy[i] = ids[i] - basic_count;
+ }
+
+ if (no_basic_stat_requested)
+ return (*dev->dev_ops->xstats_get_by_id)(dev, ids_copy,
+ values, size);
+ }
+
+ if (ids) {
+ for (i = 0; i < size; i++) {
+ if (ids[i] >= basic_count) {
+ no_ext_stat_requested = 0;
+ break;
+ }
+ }
+ }
+
+ /* Fill the xstats structure */
+ if (ids && no_ext_stat_requested)
+ ret = rte_eth_basic_stats_get(port_id, xstats);
+ else
+ ret = rte_eth_xstats_get(port_id, xstats, expected_entries);
+
+ if (ret < 0)
+ return ret;
+ num_xstats_filled = (unsigned int)ret;
+
+ /* Return all stats */
+ if (!ids) {
+ for (i = 0; i < num_xstats_filled; i++)
+ values[i] = xstats[i].value;
+ return expected_entries;
+ }
+
+ /* Filter stats */
+ for (i = 0; i < size; i++) {
+ if (ids[i] >= expected_entries) {
+ RTE_PMD_DEBUG_TRACE("ERROR: id value isn't valid\n");
+ return -1;
+ }
+ values[i] = xstats[ids[i]].value;
+ }
+ return size;
+}
+
+int
+rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
+ unsigned int n)
+{
+ struct rte_eth_dev *dev;
+ unsigned int count = 0, i;
+ signed int xcount = 0;
+ uint16_t nb_rxqs, nb_txqs;
+ int ret;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+
+ dev = &rte_eth_devices[port_id];
+
+ nb_rxqs = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+ nb_txqs = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+
+ /* Return generic statistics */
+ count = RTE_NB_STATS + (nb_rxqs * RTE_NB_RXQ_STATS) +
+ (nb_txqs * RTE_NB_TXQ_STATS);
+
+ /* implemented by the driver */
+ if (dev->dev_ops->xstats_get != NULL) {
+ /* Retrieve the xstats from the driver at the end of the
+ * xstats struct.
+ */
+ xcount = (*dev->dev_ops->xstats_get)(dev,
+ xstats ? xstats + count : NULL,
+ (n > count) ? n - count : 0);
+
+ if (xcount < 0)
+ return eth_err(port_id, xcount);
+ }
+
+ if (n < count + xcount || xstats == NULL)
+ return count + xcount;
+
+ /* now fill the xstats structure */
+ ret = rte_eth_basic_stats_get(port_id, xstats);
+ if (ret < 0)
+ return ret;
+ count = ret;