This commit implements flow control operations
to support related syscalls.
Signed-off-by: Yanling Song <son...@ramaxel.com>
---
 drivers/net/spnic/base/spnic_nic_cfg.c | 53 ++++++++++++++++++
 drivers/net/spnic/base/spnic_nic_cfg.h | 25 +++++++++
 drivers/net/spnic/spnic_ethdev.c       | 77 ++++++++++++++++++++++++++
 drivers/net/spnic/spnic_ethdev.h       |  1 +
 4 files changed, 156 insertions(+)

diff --git a/drivers/net/spnic/base/spnic_nic_cfg.c 
b/drivers/net/spnic/base/spnic_nic_cfg.c
index 0b1198eb5f..24336a2096 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.c
+++ b/drivers/net/spnic/base/spnic_nic_cfg.c
@@ -440,6 +440,59 @@ int spnic_flush_qps_res(void *hwdev)
        return 0;
 }
 
+static int spnic_cfg_hw_pause(void *hwdev, u8 opcode,
+                              struct nic_pause_config *nic_pause)
+{
+       struct spnic_cmd_pause_config pause_info;
+       u16 out_size = sizeof(pause_info);
+       int err;
+
+       memset(&pause_info, 0, sizeof(pause_info));
+
+       pause_info.port_id = spnic_physical_port_id(hwdev);
+       pause_info.opcode = opcode;
+       if (opcode == SPNIC_CMD_OP_SET) {
+               pause_info.auto_neg = nic_pause->auto_neg;
+               pause_info.rx_pause = nic_pause->rx_pause;
+               pause_info.tx_pause = nic_pause->tx_pause;
+       }
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CFG_PAUSE_INFO,
+                                    &pause_info, sizeof(pause_info),
+                                    &pause_info, &out_size);
+       if (err || !out_size || pause_info.msg_head.status) {
+               PMD_DRV_LOG(ERR, "%s pause info failed, err: %d, status: 0x%x, 
out size: 0x%x\n",
+                           opcode == SPNIC_CMD_OP_SET ? "Set" : "Get",
+                           err, pause_info.msg_head.status, out_size);
+               return -EIO;
+       }
+
+       if (opcode == SPNIC_CMD_OP_GET) {
+               nic_pause->auto_neg = pause_info.auto_neg;
+               nic_pause->rx_pause = pause_info.rx_pause;
+               nic_pause->tx_pause = pause_info.tx_pause;
+       }
+
+       return 0;
+}
+
+int spnic_set_pause_info(void *hwdev, struct nic_pause_config nic_pause)
+{
+       if (!hwdev)
+               return -EINVAL;
+
+       return spnic_cfg_hw_pause(hwdev, SPNIC_CMD_OP_SET, &nic_pause);
+}
+
+int spnic_get_pause_info(void *hwdev, struct nic_pause_config *nic_pause)
+{
+       if (!hwdev || !nic_pause)
+               return -EINVAL;
+
+
+       return spnic_cfg_hw_pause(hwdev, SPNIC_CMD_OP_GET, nic_pause);
+}
+
 static int spnic_set_function_table(void *hwdev, u32 cfg_bitmap,
                                     struct spnic_func_tbl_cfg *cfg)
 {
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.h 
b/drivers/net/spnic/base/spnic_nic_cfg.h
index 3a906b4bc3..2cdaada2ea 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.h
+++ b/drivers/net/spnic/base/spnic_nic_cfg.h
@@ -560,6 +560,31 @@ int spnic_get_link_state(void *hwdev, u8 *link_state);
  */
 int spnic_flush_qps_res(void *hwdev);
 
+/**
+ * Set pause info
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[in] nic_pause
+ *   Pause info
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_pause_info(void *hwdev, struct nic_pause_config nic_pause);
+
+/**
+ * Get pause info
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] nic_pause
+ *   Pause info
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_get_pause_info(void *hwdev, struct nic_pause_config *nic_pause);
 
 /**
  * Init nic hwdev
diff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c
index 0b5ef15373..dc7fcae10f 100644
--- a/drivers/net/spnic/spnic_ethdev.c
+++ b/drivers/net/spnic/spnic_ethdev.c
@@ -1544,6 +1544,81 @@ static int spnic_dev_promiscuous_disable(struct 
rte_eth_dev *dev)
        return 0;
 }
 
+static int spnic_dev_flow_ctrl_get(struct rte_eth_dev *dev,
+                                  struct rte_eth_fc_conf *fc_conf)
+{
+       struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       struct nic_pause_config nic_pause;
+       int err;
+
+       err = spnic_mutex_lock(&nic_dev->pause_mutuex);
+       if (err)
+               return err;
+
+       memset(&nic_pause, 0, sizeof(nic_pause));
+       err = spnic_get_pause_info(nic_dev->hwdev, &nic_pause);
+       if (err) {
+               (void)spnic_mutex_unlock(&nic_dev->pause_mutuex);
+               return err;
+       }
+
+       if (nic_dev->pause_set || !nic_pause.auto_neg) {
+               nic_pause.rx_pause = nic_dev->nic_pause.rx_pause;
+               nic_pause.tx_pause = nic_dev->nic_pause.tx_pause;
+       }
+
+       fc_conf->autoneg = nic_pause.auto_neg;
+
+       if (nic_pause.tx_pause && nic_pause.rx_pause)
+               fc_conf->mode = RTE_FC_FULL;
+       else if (nic_pause.tx_pause)
+               fc_conf->mode = RTE_FC_TX_PAUSE;
+       else if (nic_pause.rx_pause)
+               fc_conf->mode = RTE_FC_RX_PAUSE;
+       else
+               fc_conf->mode = RTE_FC_NONE;
+
+       (void)spnic_mutex_unlock(&nic_dev->pause_mutuex);
+       return 0;
+}
+
+static int spnic_dev_flow_ctrl_set(struct rte_eth_dev *dev,
+                                  struct rte_eth_fc_conf *fc_conf)
+{
+       struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       struct nic_pause_config nic_pause;
+       int err;
+
+       err = spnic_mutex_lock(&nic_dev->pause_mutuex);
+       if (err)
+               return err;
+
+       memset(&nic_pause, 0, sizeof(nic_pause));
+       if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
+           (fc_conf->mode & RTE_FC_TX_PAUSE))
+               nic_pause.tx_pause = true;
+
+       if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
+           (fc_conf->mode & RTE_FC_RX_PAUSE))
+               nic_pause.rx_pause = true;
+
+       err = spnic_set_pause_info(nic_dev->hwdev, nic_pause);
+       if (err) {
+               (void)spnic_mutex_unlock(&nic_dev->pause_mutuex);
+               return err;
+       }
+
+       nic_dev->pause_set = true;
+       nic_dev->nic_pause.rx_pause = nic_pause.rx_pause;
+       nic_dev->nic_pause.tx_pause = nic_pause.tx_pause;
+
+       PMD_DRV_LOG(INFO, "Just support set tx or rx pause info, tx: %s, rx: 
%s\n",
+                   nic_pause.tx_pause ? "on" : "off",
+                   nic_pause.rx_pause ? "on" : "off");
+
+       (void)spnic_mutex_unlock(&nic_dev->pause_mutuex);
+       return 0;
+}
 
 /**
  * Update the RSS hash key and RSS hash type.
@@ -1984,6 +2059,8 @@ static const struct eth_dev_ops spnic_pmd_ops = {
        .allmulticast_disable          = spnic_dev_allmulticast_disable,
        .promiscuous_enable            = spnic_dev_promiscuous_enable,
        .promiscuous_disable           = spnic_dev_promiscuous_disable,
+       .flow_ctrl_get                 = spnic_dev_flow_ctrl_get,
+       .flow_ctrl_set                 = spnic_dev_flow_ctrl_set,
        .rss_hash_update               = spnic_rss_hash_update,
        .rss_hash_conf_get             = spnic_rss_conf_get,
        .reta_update                   = spnic_rss_reta_update,
diff --git a/drivers/net/spnic/spnic_ethdev.h b/drivers/net/spnic/spnic_ethdev.h
index 2b59886942..be429945ac 100644
--- a/drivers/net/spnic/spnic_ethdev.h
+++ b/drivers/net/spnic/spnic_ethdev.h
@@ -76,6 +76,7 @@ struct spnic_nic_dev {
 
        bool pause_set;
        pthread_mutex_t pause_mutuex;
+       struct nic_pause_config nic_pause;
 
        struct rte_ether_addr default_addr;
        struct rte_ether_addr *mc_list;
-- 
2.27.0

Reply via email to