net/atlantic: implement device statistics
authorPavel Belous <pavel.belous@aquantia.com>
Fri, 12 Oct 2018 11:09:31 +0000 (11:09 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 18 Oct 2018 08:24:39 +0000 (10:24 +0200)
Add support for device stats, xstats and queue stats

Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: Pavel Belous <pavel.belous@aquantia.com>
doc/guides/nics/atlantic.rst
doc/guides/nics/features/atlantic.ini
drivers/net/atlantic/atl_ethdev.c
drivers/net/atlantic/atl_ethdev.h
drivers/net/atlantic/atl_rxtx.c
drivers/net/atlantic/atl_types.h

index a003ef5..1108d45 100644 (file)
@@ -13,6 +13,7 @@ Supported features
 ^^^^^^^^^^^^^^^^^^
 
 - Base L2 features
+- Port statistics
 - Checksum offload
 - Jumbo Frame upto 16K
 
index f5650ae..4056d4d 100644 (file)
@@ -13,6 +13,9 @@ CRC offload          = Y
 L3 checksum offload  = Y
 L4 checksum offload  = Y
 Packet type parsing  = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
 FW version           = Y
 Linux UIO            = Y
 ARMv8                = Y
index b4f2326..b1e7e30 100644 (file)
@@ -24,6 +24,18 @@ static void atl_dev_close(struct rte_eth_dev *dev);
 static int  atl_dev_reset(struct rte_eth_dev *dev);
 static int  atl_dev_link_update(struct rte_eth_dev *dev, int wait);
 
+static int atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+                                   struct rte_eth_xstat_name *xstats_names,
+                                   unsigned int size);
+
+static int atl_dev_stats_get(struct rte_eth_dev *dev,
+                               struct rte_eth_stats *stats);
+
+static int atl_dev_xstats_get(struct rte_eth_dev *dev,
+                             struct rte_eth_xstat *stats, unsigned int n);
+
+static void atl_dev_stats_reset(struct rte_eth_dev *dev);
+
 static int atl_fw_version_get(struct rte_eth_dev *dev, char *fw_version,
                              size_t fw_size);
 
@@ -116,6 +128,33 @@ static const struct rte_eth_desc_lim tx_desc_lim = {
        .nb_mtu_seg_max = ATL_TX_MAX_SEG,
 };
 
+#define ATL_XSTATS_FIELD(name) { \
+       #name, \
+       offsetof(struct aq_stats_s, name) \
+}
+
+struct atl_xstats_tbl_s {
+       const char *name;
+       unsigned int offset;
+};
+
+static struct atl_xstats_tbl_s atl_xstats_tbl[] = {
+       ATL_XSTATS_FIELD(uprc),
+       ATL_XSTATS_FIELD(mprc),
+       ATL_XSTATS_FIELD(bprc),
+       ATL_XSTATS_FIELD(erpt),
+       ATL_XSTATS_FIELD(uptc),
+       ATL_XSTATS_FIELD(mptc),
+       ATL_XSTATS_FIELD(bptc),
+       ATL_XSTATS_FIELD(erpr),
+       ATL_XSTATS_FIELD(ubrc),
+       ATL_XSTATS_FIELD(ubtc),
+       ATL_XSTATS_FIELD(mbrc),
+       ATL_XSTATS_FIELD(mbtc),
+       ATL_XSTATS_FIELD(bbrc),
+       ATL_XSTATS_FIELD(bbtc),
+};
+
 static const struct eth_dev_ops atl_eth_dev_ops = {
        .dev_configure        = atl_dev_configure,
        .dev_start            = atl_dev_start,
@@ -128,6 +167,13 @@ static const struct eth_dev_ops atl_eth_dev_ops = {
        /* Link */
        .link_update          = atl_dev_link_update,
 
+       /* Stats */
+       .stats_get            = atl_dev_stats_get,
+       .xstats_get           = atl_dev_xstats_get,
+       .xstats_get_names     = atl_dev_xstats_get_names,
+       .stats_reset          = atl_dev_stats_reset,
+       .xstats_reset         = atl_dev_stats_reset,
+
        .fw_version_get       = atl_fw_version_get,
        .dev_infos_get        = atl_dev_info_get,
        .dev_supported_ptypes_get = atl_dev_supported_ptypes_get,
@@ -224,6 +270,9 @@ eth_atl_dev_init(struct rte_eth_dev *eth_dev)
                        eth_dev->data->mac_addrs->addr_bytes) != 0)
                return -EINVAL;
 
+       /* Reset the hw statistics */
+       atl_dev_stats_reset(eth_dev);
+
        rte_intr_callback_register(intr_handle,
                                   atl_dev_interrupt_handler, eth_dev);
 
@@ -542,6 +591,90 @@ atl_dev_reset(struct rte_eth_dev *dev)
        return ret;
 }
 
+
+static int
+atl_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+       struct atl_adapter *adapter = ATL_DEV_TO_ADAPTER(dev);
+       struct aq_hw_s *hw = &adapter->hw;
+       struct atl_sw_stats *swstats = &adapter->sw_stats;
+       unsigned int i;
+
+       hw->aq_fw_ops->update_stats(hw);
+
+       /* Fill out the rte_eth_stats statistics structure */
+       stats->ipackets = hw->curr_stats.dma_pkt_rc;
+       stats->ibytes = hw->curr_stats.dma_oct_rc;
+       stats->imissed = hw->curr_stats.dpc;
+       stats->ierrors = hw->curr_stats.erpt;
+
+       stats->opackets = hw->curr_stats.dma_pkt_tc;
+       stats->obytes = hw->curr_stats.dma_oct_tc;
+       stats->oerrors = 0;
+
+       stats->rx_nombuf = swstats->rx_nombuf;
+
+       for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
+               stats->q_ipackets[i] = swstats->q_ipackets[i];
+               stats->q_opackets[i] = swstats->q_opackets[i];
+               stats->q_ibytes[i] = swstats->q_ibytes[i];
+               stats->q_obytes[i] = swstats->q_obytes[i];
+               stats->q_errors[i] = swstats->q_errors[i];
+       }
+       return 0;
+}
+
+static void
+atl_dev_stats_reset(struct rte_eth_dev *dev)
+{
+       struct atl_adapter *adapter = ATL_DEV_TO_ADAPTER(dev);
+       struct aq_hw_s *hw = &adapter->hw;
+
+       hw->aq_fw_ops->update_stats(hw);
+
+       /* Reset software totals */
+       memset(&hw->curr_stats, 0, sizeof(hw->curr_stats));
+
+       memset(&adapter->sw_stats, 0, sizeof(adapter->sw_stats));
+}
+
+static int
+atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+                        struct rte_eth_xstat_name *xstats_names,
+                        unsigned int size)
+{
+       unsigned int i;
+
+       if (!xstats_names)
+               return RTE_DIM(atl_xstats_tbl);
+
+       for (i = 0; i < size && i < RTE_DIM(atl_xstats_tbl); i++)
+               snprintf(xstats_names[i].name, RTE_ETH_XSTATS_NAME_SIZE, "%s",
+                       atl_xstats_tbl[i].name);
+
+       return size;
+}
+
+static int
+atl_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
+                  unsigned int n)
+{
+       struct atl_adapter *adapter = ATL_DEV_TO_ADAPTER(dev);
+       struct aq_hw_s *hw = &adapter->hw;
+       unsigned int i;
+
+       if (!stats)
+               return 0;
+
+       for (i = 0; i < n && i < RTE_DIM(atl_xstats_tbl); i++) {
+               stats[i].id = i;
+               stats[i].value = *(u64 *)((uint8_t *)&hw->curr_stats +
+                                       atl_xstats_tbl[i].offset);
+       }
+
+       return n;
+}
+
 static int
 atl_fw_version_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size)
 {
index 55a7e0d..dc48c13 100644 (file)
@@ -33,6 +33,7 @@ struct atl_interrupt {
 struct atl_adapter {
        struct aq_hw_s             hw;
        struct aq_hw_cfg_s         hw_cfg;
+       struct atl_sw_stats        sw_stats;
        struct atl_interrupt       intr;
 };
 
index 3614156..c51d24d 100644 (file)
@@ -874,7 +874,8 @@ atl_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
                                   "queue_id=%u", (unsigned int)rxq->port_id,
                                   (unsigned int)rxq->queue_id);
                                dev->data->rx_mbuf_alloc_failed++;
-                                               goto err_stop;
+                               adapter->sw_stats.rx_nombuf++;
+                               goto err_stop;
                        }
 
                        nb_hold++;
@@ -957,6 +958,9 @@ atl_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
                 * of returned packets.
                 */
                rx_pkts[nb_rx++] = rx_mbuf_first;
+               adapter->sw_stats.q_ipackets[rxq->queue_id]++;
+               adapter->sw_stats.q_ibytes[rxq->queue_id] +=
+                       rx_mbuf_first->pkt_len;
 
                PMD_RX_LOG(ERR, "add mbuf segs=%d pkt_len=%d",
                        rx_mbuf_first->nb_segs,
@@ -1102,6 +1106,8 @@ static inline void
 atl_xmit_pkt(struct aq_hw_s *hw, struct atl_tx_queue *txq,
             struct rte_mbuf *tx_pkt)
 {
+       struct atl_adapter *adapter =
+               ATL_DEV_TO_ADAPTER(&rte_eth_devices[txq->port_id]);
        uint32_t pay_len = 0;
        int tail = 0;
        struct atl_tx_entry *tx_entry;
@@ -1182,6 +1188,9 @@ atl_xmit_pkt(struct aq_hw_s *hw, struct atl_tx_queue *txq,
        txq->tx_tail = tail;
 
        txq->tx_free -= desc_count;
+
+       adapter->sw_stats.q_opackets[txq->queue_id]++;
+       adapter->sw_stats.q_obytes[txq->queue_id] += pay_len;
 }
 
 uint16_t
index e636464..56887b1 100644 (file)
@@ -140,4 +140,45 @@ struct aq_fw_ops {
        int (*set_eeprom)(struct aq_hw_s *self, u32 *data, u32 len);
 };
 
+struct atl_sw_stats {
+       u64 crcerrs;
+       u64 errbc;
+       u64 mspdc;
+       u64 mpctotal;
+       u64 mpc[8];
+       u64 mlfc;
+       u64 mrfc;
+       u64 rlec;
+       u64 lxontxc;
+       u64 lxonrxc;
+       u64 lxofftxc;
+       u64 lxoffrxc;
+       u64 pxontxc[8];
+       u64 pxonrxc[8];
+       u64 pxofftxc[8];
+       u64 pxoffrxc[8];
+       u64 gprc;
+       u64 bprc;
+       u64 mprc;
+       u64 gptc;
+       u64 gorc;
+       u64 gotc;
+       u64 tor;
+       u64 tpr;
+       u64 tpt;
+       u64 mptc;
+       u64 bptc;
+       u64 xec;
+       u64 fccrc;
+       u64 ldpcec;
+       u64 pcrc8ec;
+
+       u64 rx_nombuf;
+       u64 q_ipackets[RTE_ETHDEV_QUEUE_STAT_CNTRS];
+       u64 q_opackets[RTE_ETHDEV_QUEUE_STAT_CNTRS];
+       u64 q_ibytes[RTE_ETHDEV_QUEUE_STAT_CNTRS];
+       u64 q_obytes[RTE_ETHDEV_QUEUE_STAT_CNTRS];
+       u64 q_errors[RTE_ETHDEV_QUEUE_STAT_CNTRS];
+};
+
 #endif