+ ret = hns3vf_set_promisc_mode(hw, true, false, true);
+ if (ret)
+ hns3_err(hw, "Failed to enable allmulticast mode, ret = %d",
+ ret);
+ return ret;
+}
+
+static int
+hns3vf_dev_allmulticast_disable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (dev->data->promiscuous)
+ return 0;
+
+ ret = hns3vf_set_promisc_mode(hw, true, false, false);
+ if (ret)
+ hns3_err(hw, "Failed to disable allmulticast mode, ret = %d",
+ ret);
+ return ret;
+}
+
+static int
+hns3vf_restore_promisc(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ bool allmulti = hw->data->all_multicast ? true : false;
+
+ if (hw->data->promiscuous)
+ return hns3vf_set_promisc_mode(hw, true, true, true);
+
+ return hns3vf_set_promisc_mode(hw, true, false, allmulti);
+}
+
+static int
+hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
+ bool mmap, enum hns3_ring_type queue_type,
+ uint16_t queue_id)
+{
+ struct hns3_vf_bind_vector_msg bind_msg;
+ const char *op_str;
+ uint16_t code;
+ int ret;
+
+ memset(&bind_msg, 0, sizeof(bind_msg));
+ code = mmap ? HNS3_MBX_MAP_RING_TO_VECTOR :
+ HNS3_MBX_UNMAP_RING_TO_VECTOR;
+ bind_msg.vector_id = vector_id;
+
+ if (queue_type == HNS3_RING_TYPE_RX)
+ bind_msg.param[0].int_gl_index = HNS3_RING_GL_RX;
+ else
+ bind_msg.param[0].int_gl_index = HNS3_RING_GL_TX;
+
+ bind_msg.param[0].ring_type = queue_type;
+ bind_msg.ring_num = 1;
+ bind_msg.param[0].tqp_index = queue_id;
+ op_str = mmap ? "Map" : "Unmap";
+ ret = hns3_send_mbx_msg(hw, code, 0, (uint8_t *)&bind_msg,
+ sizeof(bind_msg), false, NULL, 0);
+ if (ret)
+ hns3_err(hw, "%s TQP %d fail, vector_id is %d, ret is %d.",
+ op_str, queue_id, bind_msg.vector_id, ret);
+
+ return ret;
+}
+
+static int
+hns3vf_init_ring_with_vector(struct hns3_hw *hw)
+{
+ uint8_t vec;
+ int ret;
+ int i;
+
+ /*
+ * In hns3 network engine, vector 0 is always the misc interrupt of this
+ * function, vector 1~N can be used respectively for the queues of the
+ * function. Tx and Rx queues with the same number share the interrupt
+ * vector. In the initialization clearing the all hardware mapping
+ * relationship configurations between queues and interrupt vectors is
+ * needed, so some error caused by the residual configurations, such as
+ * the unexpected Tx interrupt, can be avoid. Because of the hardware
+ * constraints in hns3 hardware engine, we have to implement clearing
+ * the mapping relationship configurations by binding all queues to the
+ * last interrupt vector and reserving the last interrupt vector. This
+ * method results in a decrease of the maximum queues when upper
+ * applications call the rte_eth_dev_configure API function to enable
+ * Rx interrupt.
+ */
+ vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
+ /* vec - 1: the last interrupt is reserved */
+ hw->intr_tqps_num = vec > hw->tqps_num ? hw->tqps_num : vec - 1;
+ for (i = 0; i < hw->intr_tqps_num; i++) {
+ /*
+ * Set gap limiter and rate limiter configuration of queue's
+ * interrupt.
+ */
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
+
+ ret = hns3vf_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_TX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF fail to unbind TX ring(%d) with "
+ "vector: %d, ret=%d", i, vec, ret);
+ return ret;
+ }
+
+ ret = hns3vf_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF fail to unbind RX ring(%d) with "
+ "vector: %d, ret=%d", i, vec, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3vf_dev_configure(struct rte_eth_dev *dev)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ struct rte_eth_conf *conf = &dev->data->dev_conf;
+ enum rte_eth_rx_mq_mode mq_mode = conf->rxmode.mq_mode;
+ uint16_t nb_rx_q = dev->data->nb_rx_queues;
+ uint16_t nb_tx_q = dev->data->nb_tx_queues;
+ struct rte_eth_rss_conf rss_conf;
+ uint16_t mtu;
+ int ret;
+
+ /*
+ * Hardware does not support individually enable/disable/reset the Tx or
+ * Rx queue in hns3 network engine. Driver must enable/disable/reset Tx
+ * and Rx queues at the same time. When the numbers of Tx queues
+ * allocated by upper applications are not equal to the numbers of Rx
+ * queues, driver needs to setup fake Tx or Rx queues to adjust numbers
+ * of Tx/Rx queues. otherwise, network engine can not work as usual. But
+ * these fake queues are imperceptible, and can not be used by upper
+ * applications.
+ */
+ ret = hns3_set_fake_rx_or_tx_queues(dev, nb_rx_q, nb_tx_q);
+ if (ret) {
+ hns3_err(hw, "Failed to set rx/tx fake queues: %d", ret);
+ return ret;
+ }
+
+ hw->adapter_state = HNS3_NIC_CONFIGURING;
+ if (conf->link_speeds & ETH_LINK_SPEED_FIXED) {
+ hns3_err(hw, "setting link speed/duplex not supported");
+ ret = -EINVAL;
+ goto cfg_err;
+ }
+
+ /* When RSS is not configured, redirect the packet queue 0 */
+ if ((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG) {
+ conf->rxmode.offloads |= DEV_RX_OFFLOAD_RSS_HASH;
+ rss_conf = conf->rx_adv_conf.rss_conf;
+ if (rss_conf.rss_key == NULL) {
+ rss_conf.rss_key = rss_cfg->key;
+ rss_conf.rss_key_len = HNS3_RSS_KEY_SIZE;
+ }
+
+ ret = hns3_dev_rss_hash_update(dev, &rss_conf);
+ if (ret)
+ goto cfg_err;
+ }
+
+ /*
+ * If jumbo frames are enabled, MTU needs to be refreshed
+ * according to the maximum RX packet length.
+ */
+ if (conf->rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) {
+ /*
+ * Security of max_rx_pkt_len is guaranteed in dpdk frame.
+ * Maximum value of max_rx_pkt_len is HNS3_MAX_FRAME_LEN, so it
+ * can safely assign to "uint16_t" type variable.
+ */
+ mtu = (uint16_t)HNS3_PKTLEN_TO_MTU(conf->rxmode.max_rx_pkt_len);
+ ret = hns3vf_dev_mtu_set(dev, mtu);
+ if (ret)
+ goto cfg_err;
+ dev->data->mtu = mtu;
+ }
+
+ ret = hns3vf_dev_configure_vlan(dev);
+ if (ret)
+ goto cfg_err;
+
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ return 0;
+
+cfg_err:
+ (void)hns3_set_fake_rx_or_tx_queues(dev, 0, 0);
+ hw->adapter_state = HNS3_NIC_INITIALIZED;
+
+ return ret;
+}
+
+static int
+hns3vf_config_mtu(struct hns3_hw *hw, uint16_t mtu)
+{
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_MTU, 0, (const uint8_t *)&mtu,
+ sizeof(mtu), true, NULL, 0);
+ if (ret)
+ hns3_err(hw, "Failed to set mtu (%u) for vf: %d", mtu, ret);
+
+ return ret;
+}
+
+static int
+hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint32_t frame_size = mtu + HNS3_ETH_OVERHEAD;
+ int ret;
+
+ /*
+ * The hns3 PF/VF devices on the same port share the hardware MTU
+ * configuration. Currently, we send mailbox to inform hns3 PF kernel
+ * ethdev driver to finish hardware MTU configuration in hns3 VF PMD
+ * driver, there is no need to stop the port for hns3 VF device, and the
+ * MTU value issued by hns3 VF PMD driver must be less than or equal to
+ * PF's MTU.
+ */
+ if (rte_atomic16_read(&hw->reset.resetting)) {
+ hns3_err(hw, "Failed to set mtu during resetting");
+ return -EIO;
+ }
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3vf_config_mtu(hw, mtu);