Implement ethdev generic cache stash operations for igb PMD
using PCIe TPH (Transaction Processing Hints) as the underlying
mechanism.

The implementation supports:
- Query TPH based stash capabilities
- Device-level global enable/disable of TPH
- Per-queue TPH stashing configuration with target lcore
- Configure stashing objects (Rx descriptor, payload, etc.)

Signed-off-by: Chengwen Feng <[email protected]>
---
 drivers/net/intel/e1000/base/e1000_hw.h |   2 +
 drivers/net/intel/e1000/base/e1000_vf.h |   2 +
 drivers/net/intel/e1000/igb_ethdev.c    | 221 ++++++++++++++++++++++++
 3 files changed, 225 insertions(+)

diff --git a/drivers/net/intel/e1000/base/e1000_hw.h 
b/drivers/net/intel/e1000/base/e1000_hw.h
index 9b1fafd75c..3e8e21b194 100644
--- a/drivers/net/intel/e1000/base/e1000_hw.h
+++ b/drivers/net/intel/e1000/base/e1000_hw.h
@@ -1092,6 +1092,8 @@ struct e1000_hw {
        u16 vendor_id;
 
        u8  revision_id;
+
+       u8 tph_mode;
 };
 
 #include "e1000_82541.h"
diff --git a/drivers/net/intel/e1000/base/e1000_vf.h 
b/drivers/net/intel/e1000/base/e1000_vf.h
index 4bec21c935..dd3cef254e 100644
--- a/drivers/net/intel/e1000/base/e1000_vf.h
+++ b/drivers/net/intel/e1000/base/e1000_vf.h
@@ -248,6 +248,8 @@ struct e1000_hw {
        u16 vendor_id;
 
        u8  revision_id;
+
+       u8 tph_mode;
 };
 
 enum e1000_promisc_type {
diff --git a/drivers/net/intel/e1000/igb_ethdev.c 
b/drivers/net/intel/e1000/igb_ethdev.c
index ef1599ac38..7aea37d017 100644
--- a/drivers/net/intel/e1000/igb_ethdev.c
+++ b/drivers/net/intel/e1000/igb_ethdev.c
@@ -241,6 +241,10 @@ static int igb_tx_burst_mode_get(struct rte_eth_dev *dev,
        __rte_unused uint16_t queue_id, struct rte_eth_burst_mode *mode);
 static int igb_rx_burst_mode_get(struct rte_eth_dev *dev,
        __rte_unused uint16_t queue_id, struct rte_eth_burst_mode *mode);
+static int eth_igb_cache_stash_get(struct rte_eth_dev *dev,
+                                  struct rte_eth_cache_stash_capability *capa);
+static int eth_igb_cache_stash_set(struct rte_eth_dev *dev, enum 
rte_eth_cache_stash_op op,
+                                  struct rte_eth_cache_stash_config *config);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -402,6 +406,8 @@ static const struct eth_dev_ops eth_igb_ops = {
        .timesync_read_time   = igb_timesync_read_time,
        .timesync_write_time  = igb_timesync_write_time,
        .read_clock                   = eth_igb_read_clock,
+       .cache_stash_get      = eth_igb_cache_stash_get,
+       .cache_stash_set      = eth_igb_cache_stash_set,
 };
 
 /*
@@ -5692,6 +5698,221 @@ igb_filter_restore(struct rte_eth_dev *dev)
        return 0;
 }
 
+static int
+eth_igb_cache_stash_get(struct rte_eth_dev *dev, struct 
rte_eth_cache_stash_capability *capa)
+{
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       uint32_t support_modes, st_table_sz;
+       int ret;
+
+       ret = rte_pci_tph_query(pci_dev, &support_modes, &st_table_sz);
+       if (ret != 0)
+               return -ENOTSUP;
+       capa->supported_types = RTE_ETH_CACHE_STASH_TYPE_TPH;
+       capa->supported_objects = RTE_ETH_CACHE_STASH_OBJ_RX_DESC |
+                                 RTE_ETH_CACHE_STASH_OBJ_RX_HEADER |
+                                 RTE_ETH_CACHE_STASH_OBJ_RX_PAYLOAD |
+                                 RTE_ETH_CACHE_STASH_OBJ_TX_DESC |
+                                 RTE_ETH_CACHE_STASH_OBJ_TX_HEADER |
+                                 RTE_ETH_CACHE_STASH_OBJ_TX_PAYLOAD;
+       return 0;
+}
+
+static int
+eth_igb_cache_stash_dev_enable(struct rte_eth_dev *dev,
+                              struct rte_eth_cache_stash_config *config)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       uint32_t support_modes, st_table_sz;
+       uint32_t mode;
+       int ret;
+
+       if (hw->tph_mode != 0) {
+               PMD_DRV_LOG(ERR, "Already enable tph_mode=%u", hw->tph_mode);
+               return -EINVAL;
+       }
+
+       if (config->dev.type != RTE_ETH_CACHE_STASH_TYPE_TPH) {
+               PMD_DRV_LOG(ERR, "Unsupported stash type=%u!", 
config->dev.type);
+               return -ENOTSUP;
+       }
+
+       ret = rte_pci_tph_query(pci_dev, &support_modes, &st_table_sz);
+       if (ret != 0) {
+               PMD_DRV_LOG(ERR, "Query TPH failed! ret=%d", ret);
+               return -ENOTSUP;
+       }
+
+       if (support_modes & RTE_PCI_TPH_MODE_IV)
+               mode = RTE_PCI_TPH_MODE_IV;
+       else if (support_modes & RTE_PCI_TPH_MODE_DS)
+               mode = RTE_PCI_TPH_MODE_DS;
+       else
+               return -ENOTSUP;
+       ret = rte_pci_tph_enable(pci_dev, mode);
+       if (ret == 0)
+               hw->tph_mode = mode;
+
+       return ret;
+}
+
+static void
+eth_igb_cache_stash_dev_clear(struct rte_eth_dev *dev)
+{
+       uint32_t nb_queues = RTE_MAX(dev->data->nb_rx_queues, 
dev->data->nb_tx_queues);
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_pci_tph_entry ent = {0};
+       uint32_t reg;
+       uint32_t i;
+
+       for (i = 0; i < nb_queues; i++) {
+               ent.cpu = UINT32_MAX;
+               ent.index = i;
+               rte_pci_tph_st_set(pci_dev, &ent, 1);
+               reg = E1000_READ_REG(hw, E1000_RXCTL(i));
+               reg &= ~RTE_BIT32(0);
+               reg &= ~RTE_BIT32(1);
+               reg &= ~RTE_BIT32(2);
+               reg &= ~RTE_BIT32(3);
+               reg &= ~RTE_SHIFT_VAL32(0xFF, 24);
+               E1000_WRITE_REG(hw, E1000_RXCTL(i), reg);
+       }
+}
+
+static int
+eth_igb_cache_stash_dev_disable(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       int ret;
+
+       if (hw->tph_mode == 0) {
+               PMD_DRV_LOG(ERR, "Already disable TPH!");
+               return -EINVAL;
+       }
+
+       eth_igb_cache_stash_dev_clear(dev);
+       ret = rte_pci_tph_disable(pci_dev);
+       if (ret == 0)
+               hw->tph_mode = 0;
+
+       return ret;
+}
+
+static int
+eth_igb_cache_stash_queue_enable(struct rte_eth_dev *dev,
+                                struct rte_eth_cache_stash_config *config)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       uint32_t queue_id = config->queue.queue_id;
+       struct rte_pci_tph_entry ent = {0};
+       uint32_t reg;
+       uint16_t st;
+       int ret;
+
+       if (hw->tph_mode == 0) {
+               PMD_DRV_LOG(ERR, "Device TPH was not enabled!");
+               return -EINVAL;
+       }
+
+       if (queue_id > RTE_MAX(dev->data->nb_rx_queues, 
dev->data->nb_tx_queues)) {
+               PMD_DRV_LOG(ERR, "Invalid queue_id when enable stash!");
+               return -EINVAL;
+       }
+
+       ent.cpu = config->queue.lcore_id;
+       ent.index = queue_id;
+       ret = rte_pci_tph_st_get(pci_dev, &ent, 1);
+       if (ret != 0) {
+               PMD_DRV_LOG(ERR, "Failed to get device queue=%u st of cpu=%u 
ret=%u",
+                           queue_id, config->queue.lcore_id, ret);
+               return ret;
+       }
+       st = ent.st;
+
+       reg = E1000_READ_REG(hw, E1000_RXCTL(queue_id));
+       PMD_DRV_LOG(DEBUG, "[Enable] Queue=%u rxctl register init val=0x%x", 
queue_id, reg);
+       if (config->queue.objects & RTE_ETH_CACHE_STASH_OBJ_RX_DESC) {
+               reg |= RTE_BIT32(0);
+               reg |= RTE_BIT32(1);
+       } else {
+               reg &= ~RTE_BIT32(0);
+               reg &= ~RTE_BIT32(1);
+       }
+       if (config->queue.objects & RTE_ETH_CACHE_STASH_OBJ_RX_HEADER)
+               reg |= RTE_BIT32(2);
+       else
+               reg &= ~RTE_BIT32(2);
+       if (config->queue.objects & RTE_ETH_CACHE_STASH_OBJ_RX_PAYLOAD)
+               reg |= RTE_BIT32(3);
+       else
+               reg &= ~RTE_BIT32(3);
+       /* I350 must encoding st in high 8bit, and ST in config-space is no 
needed! */
+       reg |= RTE_SHIFT_VAL32(st, 24);
+       E1000_WRITE_REG(hw, E1000_RXCTL(queue_id), reg);
+       PMD_DRV_LOG(DEBUG, "[Enable] Queue=%u rxctl register after val=0x%x", 
queue_id, reg);
+
+       PMD_DRV_LOG(DEBUG, "[Enable] Enable device queue=%u st of cpu=%u 
success!",
+                           queue_id, config->queue.lcore_id);
+
+       return 0;
+}
+
+static int
+eth_igb_cache_stash_queue_disable(struct rte_eth_dev *dev,
+                                 struct rte_eth_cache_stash_config *config)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t queue_id = config->queue.queue_id;
+       uint32_t reg;
+
+       if (hw->tph_mode == 0) {
+               PMD_DRV_LOG(ERR, "Device TPH was not enabled!");
+               return -EINVAL;
+       }
+
+       if (queue_id > RTE_MAX(dev->data->nb_rx_queues, 
dev->data->nb_tx_queues)) {
+               PMD_DRV_LOG(ERR, "Invalid queue_id when enable stash!");
+               return -EINVAL;
+       }
+
+       reg = E1000_READ_REG(hw, E1000_RXCTL(queue_id));
+       PMD_DRV_LOG(DEBUG, "[Disable] Queue=%u rxctl register init val=0x%x", 
queue_id, reg);
+       reg &= ~RTE_BIT32(0);
+       reg &= ~RTE_BIT32(1);
+       reg &= ~RTE_BIT32(2);
+       reg &= ~RTE_BIT32(3);
+       reg &= ~RTE_SHIFT_VAL32(0xFF, 24);
+       E1000_WRITE_REG(hw, E1000_RXCTL(queue_id), reg);
+       PMD_DRV_LOG(DEBUG, "[Disable] Queue=%u rxctl register after val=0x%x", 
queue_id, reg);
+
+       PMD_DRV_LOG(DEBUG, "[Disable] disable device queue=%u st of cpu=%u 
success!",
+                           queue_id, config->queue.lcore_id);
+
+       return 0;
+}
+
+static int
+eth_igb_cache_stash_set(struct rte_eth_dev *dev, enum rte_eth_cache_stash_op 
op,
+                       struct rte_eth_cache_stash_config *config)
+{
+       switch (op) {
+       case RTE_ETH_CACHE_STASH_OP_DEV_ENABLE:
+               return eth_igb_cache_stash_dev_enable(dev, config);
+       case RTE_ETH_CACHE_STASH_OP_DEV_DISABLE:
+               return eth_igb_cache_stash_dev_disable(dev);
+       case RTE_ETH_CACHE_STASH_OP_QUEUE_ENABLE:
+               return eth_igb_cache_stash_queue_enable(dev, config);
+       case RTE_ETH_CACHE_STASH_OP_QUEUE_DISABLE:
+               return eth_igb_cache_stash_queue_disable(dev, config);
+       default:
+               return -ENOTSUP;
+       }
+}
+
 RTE_PMD_REGISTER_PCI(net_e1000_igb, rte_igb_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_e1000_igb, pci_id_igb_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_e1000_igb, "* igb_uio | uio_pci_generic | 
vfio-pci");
-- 
2.17.1

Reply via email to