@@ -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 = spnic_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)
{
@@ -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
@@ -1525,6 +1525,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.
@@ -1965,6 +2040,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,
@@ -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;