#include <rte_bus_pci.h>
#include <rte_common.h>
#include <rte_cycles.h>
+#include <rte_geneve.h>
#include <rte_vxlan.h>
#include <ethdev_driver.h>
#include <rte_io.h>
uint64_t end;
int ret;
- ret = hns3_tqp_enable(hw, queue_id, false);
- if (ret)
- return ret;
-
/*
* In current version VF is not supported when PF is driven by DPDK
* driver, all task queue pairs are mapped to PF function, so PF's queue
uint8_t msg_data[2];
int ret;
- /* Disable VF's queue before send queue reset msg to PF */
- ret = hns3_tqp_enable(hw, queue_id, false);
- if (ret)
- return ret;
-
memcpy(msg_data, &queue_id, sizeof(uint16_t));
ret = hns3_send_mbx_msg(hw, HNS3_MBX_QUEUE_RESET, 0, msg_data,
}
static int
-hns3_reset_tqp(struct hns3_adapter *hns, uint16_t queue_id)
+hns3_reset_rcb_cmd(struct hns3_hw *hw, uint8_t *reset_status)
{
- struct hns3_hw *hw = &hns->hw;
+ struct hns3_reset_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
- if (hns->is_vf)
- return hns3vf_reset_tqp(hw, queue_id);
- else
- return hns3pf_reset_tqp(hw, queue_id);
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_RST_TRIGGER, false);
+ req = (struct hns3_reset_cmd *)desc.data;
+ hns3_set_bit(req->mac_func_reset, HNS3_CFG_RESET_RCB_B, 1);
+
+ /*
+ * The start qid should be the global qid of the first tqp of the
+ * function which should be reset in this port. Since our PF not
+ * support take over of VFs, so we only need to reset function 0,
+ * and its start qid is always 0.
+ */
+ req->fun_reset_rcb_vqid_start = rte_cpu_to_le_16(0);
+ req->fun_reset_rcb_vqid_num = rte_cpu_to_le_16(hw->cfg_max_queues);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "fail to send rcb reset cmd, ret = %d.", ret);
+ return ret;
+ }
+
+ *reset_status = req->fun_reset_rcb_return_status;
+ return 0;
+}
+
+static int
+hns3pf_reset_all_tqps(struct hns3_hw *hw)
+{
+#define HNS3_RESET_RCB_NOT_SUPPORT 0U
+#define HNS3_RESET_ALL_TQP_SUCCESS 1U
+ uint8_t reset_status;
+ int ret;
+ int i;
+
+ ret = hns3_reset_rcb_cmd(hw, &reset_status);
+ if (ret)
+ return ret;
+
+ /*
+ * If the firmware version is low, it may not support the rcb reset
+ * which means reset all the tqps at a time. In this case, we should
+ * reset tqps one by one.
+ */
+ if (reset_status == HNS3_RESET_RCB_NOT_SUPPORT) {
+ for (i = 0; i < hw->cfg_max_queues; i++) {
+ ret = hns3pf_reset_tqp(hw, i);
+ if (ret) {
+ hns3_err(hw,
+ "fail to reset tqp, queue_id = %d, ret = %d.",
+ i, ret);
+ return ret;
+ }
+ }
+ } else if (reset_status != HNS3_RESET_ALL_TQP_SUCCESS) {
+ hns3_err(hw, "fail to reset all tqps, reset_status = %u.",
+ reset_status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+hns3vf_reset_all_tqps(struct hns3_hw *hw)
+{
+#define HNS3VF_RESET_ALL_TQP_DONE 1U
+ uint8_t reset_status;
+ uint8_t msg_data[2];
+ int ret;
+ int i;
+
+ memset(msg_data, 0, sizeof(uint16_t));
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_QUEUE_RESET, 0, msg_data,
+ sizeof(msg_data), true, &reset_status,
+ sizeof(reset_status));
+ if (ret) {
+ hns3_err(hw, "fail to send rcb reset mbx, ret = %d.", ret);
+ return ret;
+ }
+
+ if (reset_status == HNS3VF_RESET_ALL_TQP_DONE)
+ return 0;
+
+ /*
+ * If the firmware version or kernel PF version is low, it may not
+ * support the rcb reset which means reset all the tqps at a time.
+ * In this case, we should reset tqps one by one.
+ */
+ for (i = 1; i < hw->cfg_max_queues; i++) {
+ ret = hns3vf_reset_tqp(hw, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int
struct hns3_hw *hw = &hns->hw;
int ret, i;
+ /* Disable all queues before reset all queues */
for (i = 0; i < hw->cfg_max_queues; i++) {
- ret = hns3_reset_tqp(hns, i);
+ ret = hns3_tqp_enable(hw, i, false);
if (ret) {
- hns3_err(hw, "Failed to reset No.%d queue: %d", i, ret);
+ hns3_err(hw,
+ "fail to disable tqps before tqps reset, ret = %d.",
+ ret);
return ret;
}
}
- return 0;
+
+ if (hns->is_vf)
+ return hns3vf_reset_all_tqps(hw);
+ else
+ return hns3pf_reset_all_tqps(hw);
}
static int
HNS3_RING_TX_TAIL_REG);
txq->min_tx_pkt_len = hw->min_tx_pkt_len;
txq->tso_mode = hw->tso_mode;
+ txq->udp_cksum_mode = hw->udp_cksum_mode;
memset(&txq->basic_stats, 0, sizeof(struct hns3_tx_basic_stats));
memset(&txq->dfx_stats, 0, sizeof(struct hns3_tx_dfx_stats));
}
#endif
+static uint16_t
+hns3_udp_cksum_help(struct rte_mbuf *m)
+{
+ uint64_t ol_flags = m->ol_flags;
+ uint16_t cksum = 0;
+ uint32_t l4_len;
+
+ if (ol_flags & PKT_TX_IPV4) {
+ struct rte_ipv4_hdr *ipv4_hdr = rte_pktmbuf_mtod_offset(m,
+ struct rte_ipv4_hdr *, m->l2_len);
+ l4_len = rte_be_to_cpu_16(ipv4_hdr->total_length) - m->l3_len;
+ } else {
+ struct rte_ipv6_hdr *ipv6_hdr = rte_pktmbuf_mtod_offset(m,
+ struct rte_ipv6_hdr *, m->l2_len);
+ l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
+ }
+
+ rte_raw_cksum_mbuf(m, m->l2_len + m->l3_len, l4_len, &cksum);
+
+ cksum = ~cksum;
+ /*
+ * RFC 768:If the computed checksum is zero for UDP, it is transmitted
+ * as all ones
+ */
+ if (cksum == 0)
+ cksum = 0xffff;
+
+ return (uint16_t)cksum;
+}
+
+static bool
+hns3_validate_tunnel_cksum(struct hns3_tx_queue *tx_queue, struct rte_mbuf *m)
+{
+ uint64_t ol_flags = m->ol_flags;
+ struct rte_udp_hdr *udp_hdr;
+ uint16_t dst_port;
+
+ if (tx_queue->udp_cksum_mode == HNS3_SPECIAL_PORT_HW_CKSUM_MODE ||
+ ol_flags & PKT_TX_TUNNEL_MASK ||
+ (ol_flags & PKT_TX_L4_MASK) != PKT_TX_UDP_CKSUM)
+ return true;
+ /*
+ * A UDP packet with the same dst_port as VXLAN\VXLAN_GPE\GENEVE will
+ * be recognized as a tunnel packet in HW. In this case, if UDP CKSUM
+ * offload is set and the tunnel mask has not been set, the CKSUM will
+ * be wrong since the header length is wrong and driver should complete
+ * the CKSUM to avoid CKSUM error.
+ */
+ udp_hdr = rte_pktmbuf_mtod_offset(m, struct rte_udp_hdr *,
+ m->l2_len + m->l3_len);
+ dst_port = rte_be_to_cpu_16(udp_hdr->dst_port);
+ switch (dst_port) {
+ case RTE_VXLAN_DEFAULT_PORT:
+ case RTE_VXLAN_GPE_DEFAULT_PORT:
+ case RTE_GENEVE_DEFAULT_PORT:
+ udp_hdr->dgram_cksum = hns3_udp_cksum_help(m);
+ m->ol_flags = ol_flags & ~PKT_TX_L4_MASK;
+ return false;
+ default:
+ return true;
+ }
+}
+
static int
hns3_prep_pkt_proc(struct hns3_tx_queue *tx_queue, struct rte_mbuf *m)
{
return ret;
}
+ if (!hns3_validate_tunnel_cksum(tx_queue, m))
+ return 0;
+
hns3_outer_header_cksum_prepare(m);
return 0;