From 563455467f3d3523a4f51db05ccaae5bd1809c71 Mon Sep 17 00:00:00 2001
From: Intel <intel.com>
Date: Thu, 20 Dec 2012 00:00:00 +0100
Subject: [PATCH] ixgbe: stats per queue

Signed-off-by: Intel
---
 lib/librte_pmd_ixgbe/ixgbe_ethdev.c | 106 +++++++++++++++++++++++++++-
 lib/librte_pmd_ixgbe/ixgbe_ethdev.h |  11 ++-
 2 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
index 6d804569ed..613e49df88 100644
--- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
+++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
@@ -85,6 +85,8 @@
 #define IXGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */
 #define IXGBE_LINK_UP_CHECK_TIMEOUT   1000 /* ms */
 
+#define IXGBE_QUEUE_STAT_COUNTERS (sizeof(hw_stats->qprc) / sizeof(hw_stats->qprc[0]))
+
 static int eth_ixgbe_dev_init(struct eth_driver *eth_drv,
 		struct rte_eth_dev *eth_dev);
 static int  ixgbe_dev_configure(struct rte_eth_dev *dev, uint16_t nb_rx_q,
@@ -101,6 +103,10 @@ static int ixgbe_dev_link_update(struct rte_eth_dev *dev,
 static void ixgbe_dev_stats_get(struct rte_eth_dev *dev,
 				struct rte_eth_stats *stats);
 static void ixgbe_dev_stats_reset(struct rte_eth_dev *dev);
+static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
+					     uint16_t queue_id,
+					     uint8_t stat_idx,
+					     uint8_t is_rx);
 static void ixgbe_dev_info_get(struct rte_eth_dev *dev,
 				struct rte_eth_dev_info *dev_info);
 static void ixgbe_vlan_filter_set(struct rte_eth_dev *dev,
@@ -189,6 +195,7 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.link_update          = ixgbe_dev_link_update,
 	.stats_get            = ixgbe_dev_stats_get,
 	.stats_reset          = ixgbe_dev_stats_reset,
+	.queue_stats_mapping_set = ixgbe_dev_queue_stats_mapping_set,
 	.dev_infos_get        = ixgbe_dev_info_get,
 	.vlan_filter_set      = ixgbe_vlan_filter_set,
 	.rx_queue_setup       = ixgbe_dev_rx_queue_setup,
@@ -326,12 +333,97 @@ static void
 ixgbe_reset_qstat_mappings(struct ixgbe_hw *hw)
 {
 	uint32_t i;
-	for(i = 0; i != 16; i++) {
+
+	for(i = 0; i != IXGBE_NB_STAT_MAPPING_REGS; i++) {
 		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), 0);
 		IXGBE_WRITE_REG(hw, IXGBE_TQSM(i), 0);
 	}
 }
 
+
+static int
+ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
+				  uint16_t queue_id,
+				  uint8_t stat_idx,
+				  uint8_t is_rx)
+{
+#define QSM_REG_NB_BITS_PER_QMAP_FIELD 8
+#define NB_QMAP_FIELDS_PER_QSM_REG 4
+#define QMAP_FIELD_RESERVED_BITS_MASK 0x0f
+
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+	struct ixgbe_stat_mapping_registers *stat_mappings =
+		IXGBE_DEV_PRIVATE_TO_STAT_MAPPINGS(eth_dev->data->dev_private);
+	uint32_t qsmr_mask = 0;
+	uint32_t clearing_mask = QMAP_FIELD_RESERVED_BITS_MASK;
+	uint32_t q_map;
+	uint8_t n, offset;
+
+	if ((hw->mac.type != ixgbe_mac_82599EB) && (hw->mac.type != ixgbe_mac_X540))
+		return -ENOSYS;
+
+	PMD_INIT_LOG(INFO, "Setting port %d, %s queue_id %d to stat index %d\n",
+		     (int)(eth_dev->data->port_id), is_rx ? "RX" : "TX", queue_id, stat_idx);
+
+	n = queue_id / NB_QMAP_FIELDS_PER_QSM_REG;
+	if (n >= IXGBE_NB_STAT_MAPPING_REGS) {
+		PMD_INIT_LOG(ERR, "Nb of stat mapping registers exceeded\n");
+		return -EIO;
+	}
+	offset = queue_id % NB_QMAP_FIELDS_PER_QSM_REG;
+
+	/* Now clear any previous stat_idx set */
+	clearing_mask <<= (QSM_REG_NB_BITS_PER_QMAP_FIELD * offset);
+	if (!is_rx)
+		stat_mappings->tqsm[n] &= ~clearing_mask;
+	else
+		stat_mappings->rqsmr[n] &= ~clearing_mask;
+
+	q_map = (uint32_t)stat_idx;
+	q_map &= QMAP_FIELD_RESERVED_BITS_MASK;
+	qsmr_mask = q_map << (QSM_REG_NB_BITS_PER_QMAP_FIELD * offset);
+	if (!is_rx)
+		stat_mappings->tqsm[n] |= qsmr_mask;
+	else
+		stat_mappings->rqsmr[n] |= qsmr_mask;
+
+	PMD_INIT_LOG(INFO, "Set port %d, %s queue_id %d to stat index %d\n"
+		     "%s[%d] = 0x%08x\n",
+		     (int)(eth_dev->data->port_id), is_rx ? "RX" : "TX", queue_id, stat_idx,
+		     is_rx ? "RQSMR" : "TQSM",n, is_rx ? stat_mappings->rqsmr[n] : stat_mappings->tqsm[n]);
+
+	/* Now write the mapping in the appropriate register */
+	if (is_rx) {
+		PMD_INIT_LOG(INFO, "Write 0x%x to RX IXGBE stat mapping reg:%d\n",
+			     stat_mappings->rqsmr[n], n);
+		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(n), stat_mappings->rqsmr[n]);
+	}
+	else {
+		PMD_INIT_LOG(INFO, "Write 0x%x to TX IXGBE stat mapping reg:%d\n",
+			     stat_mappings->tqsm[n], n);
+		IXGBE_WRITE_REG(hw, IXGBE_TQSM(n), stat_mappings->tqsm[n]);
+	}
+	return 0;
+}
+
+static void
+ixgbe_restore_statistics_mapping(struct rte_eth_dev * dev)
+{
+	struct ixgbe_stat_mapping_registers *stat_mappings =
+		IXGBE_DEV_PRIVATE_TO_STAT_MAPPINGS(dev->data->dev_private);
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int i;
+
+	/* write whatever was in stat mapping table to the NIC */
+	for (i = 0; i < IXGBE_NB_STAT_MAPPING_REGS; i++) {
+		/* rx */
+		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), stat_mappings->rqsmr[i]);
+
+		/* tx */
+		IXGBE_WRITE_REG(hw, IXGBE_TQSM(i), stat_mappings->tqsm[i]);
+	}
+}
+
 /*
  * This function is based on code in ixgbe_attach() in ixgbe/ixgbe.c.
  * It returns 0 on success.
@@ -820,6 +912,8 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
 			goto error;
 	}
 
+	ixgbe_restore_statistics_mapping(dev);
+
 	return (0);
 
 error:
@@ -927,7 +1021,7 @@ ixgbe_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 		hw_stats->pxon2offc[i] +=
 		    IXGBE_READ_REG(hw, IXGBE_PXON2OFFCNT(i));
 	}
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < IXGBE_QUEUE_STAT_COUNTERS; i++) {
 		hw_stats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
 		hw_stats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
 		hw_stats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC_L(i));
@@ -1034,6 +1128,14 @@ ixgbe_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	stats->obytes = hw_stats->gotc;
 	stats->imcasts = hw_stats->mprc;
 
+	for (i = 0; i < IXGBE_QUEUE_STAT_COUNTERS; i++) {
+		stats->q_ipackets[i] = hw_stats->qprc[i];
+		stats->q_opackets[i] = hw_stats->qptc[i];
+		stats->q_ibytes[i] = hw_stats->qbrc[i];
+		stats->q_obytes[i] = hw_stats->qbtc[i];
+		stats->q_errors[i] = hw_stats->qprdc[i];
+	}
+
 	/* Rx Errors */
 	stats->ierrors = total_missed_rx + hw_stats->crcerrs +
 		hw_stats->rlec;
diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.h b/lib/librte_pmd_ixgbe/ixgbe_ethdev.h
index 1b897384e2..2506d90e33 100644
--- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.h
+++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.h
@@ -48,7 +48,7 @@
 #define IXGBE_RXDADV_ERR_CKSUM_BIT  30
 #define IXGBE_RXDADV_ERR_CKSUM_MSK  3
 #define IXGBE_ADVTXD_MACLEN_SHIFT   9          /* Bit shift for l2_len */
-
+#define IXGBE_NB_STAT_MAPPING_REGS  32
 #define IXGBE_VFTA_SIZE 128
 
 /*
@@ -70,6 +70,11 @@ struct ixgbe_interrupt {
 	uint32_t flags;
 };
 
+struct ixgbe_stat_mapping_registers {
+	uint32_t tqsm[IXGBE_NB_STAT_MAPPING_REGS];
+	uint32_t rqsmr[IXGBE_NB_STAT_MAPPING_REGS];
+};
+
 /* local VFTA copy */
 struct ixgbe_vfta {
 	uint32_t vfta[IXGBE_VFTA_SIZE];
@@ -83,6 +88,7 @@ struct ixgbe_adapter {
 	struct ixgbe_hw_stats       stats;
 	struct ixgbe_hw_fdir_info   fdir;
 	struct ixgbe_interrupt      intr;
+	struct ixgbe_stat_mapping_registers stat_mappings;
 	struct ixgbe_vfta           shadow_vfta;
 };
 
@@ -98,6 +104,9 @@ struct ixgbe_adapter {
 #define IXGBE_DEV_PRIVATE_TO_FDIR_INFO(adapter) \
 	(&((struct ixgbe_adapter *)adapter)->fdir)
 
+#define IXGBE_DEV_PRIVATE_TO_STAT_MAPPINGS(adapter) \
+	(&((struct ixgbe_adapter *)adapter)->stat_mappings)
+
 #define IXGBE_DEV_PRIVATE_TO_VFTA(adapter) \
 	(&((struct ixgbe_adapter *)adapter)->shadow_vfta)
 
-- 
2.39.5