[04/10] net/hns3: support setting VF PVID by PF driver

Message ID 1593604482-47494-5-git-send-email-xavier.huwei@huawei.com (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers
Series misc updates for hns3 PMD driver |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Wei Hu (Xavier) July 1, 2020, 11:54 a.m. UTC
  From: Chengchang Tang <tangchengchang@huawei.com>

This patch adds support setting VF PVID by hns3 PF kernel ethdev driver
on the host by "ip link set <eth num> vf <vf id> vlan <vlan tag>"
command.

Because of the hardware constraints, the striped VLAN tag will always in
Rx descriptors which should has been dropped when PVID is enabled and the
PVID will overwrite the outer VLAN tag in Tx descriptor. So, hns3 PMD
driver need to change the processing of VLAN tags in the process of Tx
and Rx according to whether PVID is enabled.
1) If the hns3 PF kernel ethdev driver sets the PVID for VF device before
   the initialization of the related VF device, hns3 VF PMD driver should
   get the PVID state from PF driver through mailbox and update the related
   state in txq and rxq maintained by hns3 VF driver to change the process
   of Tx and Rx.
2) If the hns3 PF kernel ethdev driver sets the PVID for VF device after
   initialization of the related VF device, the PF driver will notify VF
   driver to update the PVID state. The VF driver will update the PVID
   configuration state immediately to ensure that the VLAN process in Tx
   and Rx is correct. But in the window period of this state transition,
   packets loss or packets with wrong VLAN may occur.
3) Due to hardware limitations, we only support two-layer VLAN hardware
   offload in Tx direction based on hns3 network engine, so when PVID is
   enabled, QinQ insert is no longer supported. And when PVID is enabled,
   in the following two cases:
     i) packets with more than two VLAN tags.
     ii) packets with one VLAN tag while the hardware VLAN insert is
         enabled.
   The packets will be regarded as abnormal packets and discarded by
   hardware in Tx direction. For debugging purposes, a validation check for
   these types of packets is added to the '.tx_pkt_prepare' ops
   implementation function named hns3_prep_pkts to inform users that these
   packets will be discarded.

Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 drivers/net/hns3/hns3_ethdev.c    |  5 ++--
 drivers/net/hns3/hns3_ethdev.h    |  9 +++++++
 drivers/net/hns3/hns3_ethdev_vf.c | 56 ++++++++++++++++++++++++++++++++++++---
 drivers/net/hns3/hns3_mbx.c       | 33 +++++++++++++++++++++++
 drivers/net/hns3/hns3_mbx.h       |  3 +++
 drivers/net/hns3/hns3_rxtx.c      | 47 ++++++++++++++++++++++++++++++++
 6 files changed, 147 insertions(+), 6 deletions(-)
  

Patch

diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 926efce..5a2f049 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -2476,14 +2476,13 @@  hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
 				 DEV_TX_OFFLOAD_TCP_CKSUM |
 				 DEV_TX_OFFLOAD_UDP_CKSUM |
 				 DEV_TX_OFFLOAD_SCTP_CKSUM |
-				 DEV_TX_OFFLOAD_VLAN_INSERT |
-				 DEV_TX_OFFLOAD_QINQ_INSERT |
 				 DEV_TX_OFFLOAD_MULTI_SEGS |
 				 DEV_TX_OFFLOAD_TCP_TSO |
 				 DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
 				 DEV_TX_OFFLOAD_GRE_TNL_TSO |
 				 DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
-				 info->tx_queue_offload_capa);
+				 info->tx_queue_offload_capa |
+				 hns3_txvlan_cap_get(hw));
 
 	info->rx_desc_lim = (struct rte_eth_desc_lim) {
 		.nb_max = HNS3_MAX_RING_DESC,
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 93fe2fe..a4db1c9 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -673,4 +673,13 @@  is_reset_pending(struct hns3_adapter *hns)
 	return ret;
 }
 
+static inline uint64_t
+hns3_txvlan_cap_get(struct hns3_hw *hw)
+{
+	if (hw->port_base_vlan_cfg.state)
+		return DEV_TX_OFFLOAD_VLAN_INSERT;
+	else
+		return DEV_TX_OFFLOAD_VLAN_INSERT | DEV_TX_OFFLOAD_QINQ_INSERT;
+}
+
 #endif /* _HNS3_ETHDEV_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index ccf44a1..afa79a7 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -926,14 +926,13 @@  hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
 				 DEV_TX_OFFLOAD_TCP_CKSUM |
 				 DEV_TX_OFFLOAD_UDP_CKSUM |
 				 DEV_TX_OFFLOAD_SCTP_CKSUM |
-				 DEV_TX_OFFLOAD_VLAN_INSERT |
-				 DEV_TX_OFFLOAD_QINQ_INSERT |
 				 DEV_TX_OFFLOAD_MULTI_SEGS |
 				 DEV_TX_OFFLOAD_TCP_TSO |
 				 DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
 				 DEV_TX_OFFLOAD_GRE_TNL_TSO |
 				 DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
-				 info->tx_queue_offload_capa);
+				 info->tx_queue_offload_capa |
+				 hns3_txvlan_cap_get(hw));
 
 	info->rx_desc_lim = (struct rte_eth_desc_lim) {
 		.nb_max = HNS3_MAX_RING_DESC,
@@ -1078,6 +1077,49 @@  hns3vf_check_tqp_info(struct hns3_hw *hw)
 
 	return 0;
 }
+static int
+hns3vf_get_port_base_vlan_filter_state(struct hns3_hw *hw)
+{
+	uint8_t resp_msg;
+	int ret;
+
+	ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_VLAN,
+				HNS3_MBX_GET_PORT_BASE_VLAN_STATE, NULL, 0,
+				true, &resp_msg, sizeof(resp_msg));
+	if (ret) {
+		if (ret == -ETIME) {
+			/*
+			 * Getting current port based VLAN state from PF driver
+			 * will not affect VF driver's basic function. Because
+			 * the VF driver relies on hns3 PF kernel ether driver,
+			 * to avoid introducing compatibility issues with older
+			 * version of PF driver, no failure will be returned
+			 * when the return value is ETIME. This return value has
+			 * the following scenarios:
+			 * 1) Firmware didn't return the results in time
+			 * 2) the result return by firmware is timeout
+			 * 3) the older version of kernel side PF driver does
+			 *    not support this mailbox message.
+			 * For scenarios 1 and 2, it is most likely that a
+			 * hardware error has occurred, or a hardware reset has
+			 * occurred. In this case, these errors will be caught
+			 * by other functions.
+			 */
+			PMD_INIT_LOG(WARNING,
+				"failed to get PVID state for timeout, maybe "
+				"kernel side PF driver doesn't support this "
+				"mailbox message, or firmware didn't respond.");
+			resp_msg = HNS3_PORT_BASE_VLAN_DISABLE;
+		} else {
+			PMD_INIT_LOG(ERR, "failed to get port based VLAN state,"
+				" ret = %d", ret);
+			return ret;
+		}
+	}
+	hw->port_base_vlan_cfg.state = resp_msg ?
+		HNS3_PORT_BASE_VLAN_ENABLE : HNS3_PORT_BASE_VLAN_DISABLE;
+	return 0;
+}
 
 static int
 hns3vf_get_queue_info(struct hns3_hw *hw)
@@ -1181,6 +1223,10 @@  hns3vf_get_configuration(struct hns3_hw *hw)
 	if (ret)
 		return ret;
 
+	ret = hns3vf_get_port_base_vlan_filter_state(hw);
+	if (ret)
+		return ret;
+
 	/* Get tc configuration from PF */
 	return hns3vf_get_tc_info(hw);
 }
@@ -2225,6 +2271,10 @@  hns3vf_restore_conf(struct hns3_adapter *hns)
 	if (ret)
 		goto err_vlan_table;
 
+	ret = hns3vf_get_port_base_vlan_filter_state(hw);
+	if (ret)
+		goto err_vlan_table;
+
 	ret = hns3vf_restore_rx_interrupt(hw);
 	if (ret)
 		goto err_vlan_table;
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
index 34c8c68..2510582 100644
--- a/drivers/net/hns3/hns3_mbx.c
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -23,6 +23,7 @@ 
 #include "hns3_regs.h"
 #include "hns3_logs.h"
 #include "hns3_intr.h"
+#include "hns3_rxtx.h"
 
 #define HNS3_CMD_CODE_OFFSET		2
 
@@ -327,6 +328,30 @@  hns3_handle_link_change_event(struct hns3_hw *hw,
 }
 
 static void
+hns3_update_port_base_vlan_info(struct hns3_hw *hw,
+				struct hns3_mbx_pf_to_vf_cmd *req)
+{
+#define PVID_STATE_OFFSET	1
+	uint16_t new_pvid_state = req->msg[PVID_STATE_OFFSET] ?
+		HNS3_PORT_BASE_VLAN_ENABLE : HNS3_PORT_BASE_VLAN_DISABLE;
+	/*
+	 * Currently, hardware doesn't support more than two layers VLAN offload
+	 * based on hns3 network engine, which would cause packets loss or wrong
+	 * packets for these types of packets. If the hns3 PF kernel ethdev
+	 * driver sets the PVID for VF device after initialization of the
+	 * related VF device, the PF driver will notify VF driver to update the
+	 * PVID configuration state. The VF driver will update the PVID
+	 * configuration state immediately to ensure that the VLAN process in Tx
+	 * and Rx is correct. But in the window period of this state transition,
+	 * packets loss or packets with wrong VLAN may occur.
+	 */
+	if (hw->port_base_vlan_cfg.state != new_pvid_state) {
+		hw->port_base_vlan_cfg.state = new_pvid_state;
+		hns3_update_all_queues_pvid_state(hw);
+	}
+}
+
+static void
 hns3_handle_promisc_info(struct hns3_hw *hw, uint16_t promisc_en)
 {
 	if (!promisc_en) {
@@ -399,6 +424,14 @@  hns3_dev_handle_mbx_msg(struct hns3_hw *hw)
 		case HNS3_MBX_PUSH_LINK_STATUS:
 			hns3_handle_link_change_event(hw, req);
 			break;
+		case HNS3_MBX_PUSH_VLAN_INFO:
+			/*
+			 * When the PVID configuration status of VF device is
+			 * changed by the hns3 PF kernel driver, VF driver will
+			 * receive this mailbox message from PF driver.
+			 */
+			hns3_update_port_base_vlan_info(hw, req);
+			break;
 		case HNS3_MBX_PUSH_PROMISC_INFO:
 			/*
 			 * When the trust status of VF device changed by the
diff --git a/drivers/net/hns3/hns3_mbx.h b/drivers/net/hns3/hns3_mbx.h
index d6d70f6..7f7ade1 100644
--- a/drivers/net/hns3/hns3_mbx.h
+++ b/drivers/net/hns3/hns3_mbx.h
@@ -40,6 +40,8 @@  enum HNS3_MBX_OPCODE {
 	HNS3_MBX_SET_MTU,               /* (VF -> PF) set mtu */
 	HNS3_MBX_GET_QID_IN_PF,         /* (VF -> PF) get queue id in pf */
 
+	HNS3_MBX_PUSH_VLAN_INFO = 34,   /* (PF -> VF) push port base vlan */
+
 	HNS3_MBX_PUSH_PROMISC_INFO = 36, /* (PF -> VF) push vf promisc info */
 
 	HNS3_MBX_HANDLE_VF_TBL = 38,    /* (VF -> PF) store/clear hw cfg tbl */
@@ -62,6 +64,7 @@  enum hns3_mbx_vlan_cfg_subcode {
 	HNS3_MBX_VLAN_FILTER = 0,               /* set vlan filter */
 	HNS3_MBX_VLAN_TX_OFF_CFG,               /* set tx side vlan offload */
 	HNS3_MBX_VLAN_RX_OFF_CFG,               /* set rx side vlan offload */
+	HNS3_MBX_GET_PORT_BASE_VLAN_STATE = 4,  /* get port based vlan state */
 };
 
 enum hns3_mbx_tbl_cfg_subcode {
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index d744d85..0f9825f 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -2422,6 +2422,48 @@  hns3_check_tso_pkt_valid(struct rte_mbuf *m)
 	return 0;
 }
 
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+static inline int
+hns3_vld_vlan_chk(struct hns3_tx_queue *txq, struct rte_mbuf *m)
+{
+	struct rte_ether_hdr *eh;
+	struct rte_vlan_hdr *vh;
+
+	if (!txq->pvid_state)
+		return 0;
+
+	/*
+	 * Due to hardware limitations, we only support two-layer VLAN hardware
+	 * offload in Tx direction based on hns3 network engine, so when PVID is
+	 * enabled, QinQ insert is no longer supported.
+	 * And when PVID is enabled, in the following two cases:
+	 *  i) packets with more than two VLAN tags.
+	 *  ii) packets with one VLAN tag while the hardware VLAN insert is
+	 *      enabled.
+	 * The packets will be regarded as abnormal packets and discarded by
+	 * hardware in Tx direction. For debugging purposes, a validation check
+	 * for these types of packets is added to the '.tx_pkt_prepare' ops
+	 * implementation function named hns3_prep_pkts to inform users that
+	 * these packets will be discarded.
+	 */
+	if (m->ol_flags & PKT_TX_QINQ_PKT)
+		return -EINVAL;
+
+	eh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
+	if (eh->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN)) {
+		if (m->ol_flags & PKT_TX_VLAN_PKT)
+			return -EINVAL;
+
+		/* Ensure the incoming packet is not a QinQ packet */
+		vh = (struct rte_vlan_hdr *)(eh + 1);
+		if (vh->eth_proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
 uint16_t
 hns3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
 	       uint16_t nb_pkts)
@@ -2446,6 +2488,11 @@  hns3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
 			rte_errno = -ret;
 			return i;
 		}
+
+		if (hns3_vld_vlan_chk(tx_queue, m)) {
+			rte_errno = EINVAL;
+			return i;
+		}
 #endif
 		ret = rte_net_intel_cksum_prepare(m);
 		if (ret != 0) {