DPDK patches and discussions
 help / color / mirror / Atom feed
From: Wenbo Cao <caowenbo@mucse.com>
To: stephen@networkplumber.org, Wenbo Cao <caowenbo@mucse.com>
Cc: dev@dpdk.org, ferruh.yigit@amd.com,
	andrew.rybchenko@oktetlabs.ru, yaojun@mucse.com
Subject: [PATCH v3 7/8] net/rnp add devargs runtime parsing functions
Date: Thu,  3 Aug 2023 07:52:32 +0000	[thread overview]
Message-ID: <20230803075233.3485076-8-caowenbo@mucse.com> (raw)
In-Reply-To: <20230803075233.3485076-1-caowenbo@mucse.com>

add various runtime devargs command line options
supported by this driver.

Signed-off-by: Wenbo Cao <caowenbo@mucse.com>
---
 drivers/net/rnp/rnp.h        |  22 +++++
 drivers/net/rnp/rnp_ethdev.c | 166 +++++++++++++++++++++++++++++++++++
 drivers/net/rnp/rnp_mbx_fw.c | 164 ++++++++++++++++++++++++++++++++++
 drivers/net/rnp/rnp_mbx_fw.h |  69 +++++++++++++++
 4 files changed, 421 insertions(+)

diff --git a/drivers/net/rnp/rnp.h b/drivers/net/rnp/rnp.h
index 6f216cc5ca..933cdc6007 100644
--- a/drivers/net/rnp/rnp.h
+++ b/drivers/net/rnp/rnp.h
@@ -107,6 +107,8 @@ struct rnp_eth_port {
 	struct rnp_eth_adapter *adapt;
 	uint8_t mac_addr[RTE_ETHER_ADDR_LEN];
 	struct rnp_hw *hw;
+	uint8_t rx_func_sec; /* force set io rx_func */
+	uint8_t tx_func_sec; /* force set io tx func */
 	struct rte_eth_dev *eth_dev;
 	struct rnp_port_attr attr;
 	/* Recvice Mac Address Record Table */
@@ -122,6 +124,13 @@ struct rnp_share_ops {
 	const struct rnp_mac_api *mac_api;
 } __rte_cache_aligned;
 
+enum {
+	RNP_IO_FUNC_USE_NONE = 0,
+	RNP_IO_FUNC_USE_VEC,
+	RNP_IO_FUNC_USE_SIMPLE,
+	RNP_IO_FUNC_USE_COMMON,
+};
+
 struct rnp_eth_adapter {
 	enum rnp_work_mode mode;
 	enum rnp_resource_share_m s_mode; /* Port Resource Share Policy */
@@ -135,6 +144,19 @@ struct rnp_eth_adapter {
 	int max_link_speed;
 	uint8_t num_ports; /* Cur Pf Has physical Port Num */
 	uint8_t lane_mask;
+
+	uint8_t rx_func_sec; /* force set io rx_func */
+	uint8_t tx_func_sec; /* force set io tx func*/
+	/*fw-update*/
+	bool  do_fw_update;
+	char *fw_path;
+
+	bool loopback_en;
+	bool fw_sfp_10g_1g_auto_det;
+	int fw_force_speed_1g;
+#define FOCE_SPEED_1G_NOT_SET	(-1)
+#define FOCE_SPEED_1G_DISABLED	(0)
+#define FOCE_SPEED_1G_ENABLED	(1)
 } __rte_cache_aligned;
 
 #define RNP_DEV_TO_PORT(eth_dev) \
diff --git a/drivers/net/rnp/rnp_ethdev.c b/drivers/net/rnp/rnp_ethdev.c
index ad99f99d4a..5313dae5a2 100644
--- a/drivers/net/rnp/rnp_ethdev.c
+++ b/drivers/net/rnp/rnp_ethdev.c
@@ -6,6 +6,7 @@
 #include <rte_io.h>
 #include <rte_malloc.h>
 #include <ethdev_driver.h>
+#include <rte_kvargs.h>
 
 #include "rnp.h"
 #include "rnp_api.h"
@@ -14,6 +15,13 @@
 #include "rnp_rxtx.h"
 #include "rnp_logs.h"
 
+#define RNP_HW_MAC_LOOPBACK_ARG      "hw_loopback"
+#define RNP_FW_UPDATE                "fw_update"
+#define RNP_RX_FUNC_SELECT           "rx_func_sec"
+#define RNP_TX_FUNC_SELECT           "tx_func_sec"
+#define RNP_FW_4X10G_10G_1G_DET      "fw_4x10g_10g_1g_auto_det"
+#define RNP_FW_FORCE_SPEED_1G        "fw_force_1g_speed"
+
 static int
 rnp_mac_rx_disable(struct rte_eth_dev *dev)
 {
@@ -108,6 +116,8 @@ rnp_init_port_resource(struct rnp_eth_adapter *adapter,
 	struct rnp_hw *hw = &adapter->hw;
 
 	port->adapt = adapter;
+	port->rx_func_sec = adapter->rx_func_sec;
+	port->tx_func_sec = adapter->tx_func_sec;
 	port->s_mode = adapter->s_mode;
 	port->port_stopped = 1;
 	port->hw = hw;
@@ -443,6 +453,154 @@ rnp_special_ops_init(struct rte_eth_dev *eth_dev)
 	return 0;
 }
 
+static const char *const rnp_valid_arguments[] = {
+	RNP_HW_MAC_LOOPBACK_ARG,
+	RNP_FW_UPDATE,
+	RNP_RX_FUNC_SELECT,
+	RNP_TX_FUNC_SELECT,
+	RNP_FW_4X10G_10G_1G_DET,
+	RNP_FW_FORCE_SPEED_1G,
+	NULL
+};
+
+static int
+rnp_parse_handle_devarg(const char *key, const char *value,
+			void *extra_args)
+{
+	struct rnp_eth_adapter *adapter = NULL;
+
+	if (value == NULL || extra_args == NULL)
+		return -EINVAL;
+
+	if (strcmp(key, RNP_HW_MAC_LOOPBACK_ARG) == 0) {
+		uint64_t *n = extra_args;
+		*n = (uint16_t)strtoul(value, NULL, 10);
+		if (*n > UINT16_MAX && errno == ERANGE) {
+			RNP_PMD_DRV_LOG(ERR, "invalid extra param value\n");
+			return -1;
+		}
+	} else if (strcmp(key, RNP_FW_UPDATE) == 0) {
+		adapter = (struct rnp_eth_adapter *)extra_args;
+		adapter->do_fw_update = true;
+		adapter->fw_path = strdup(value);
+	} else if (strcmp(key, RNP_FW_4X10G_10G_1G_DET) == 0) {
+		adapter = (struct rnp_eth_adapter *)extra_args;
+		if (adapter->num_ports == 2 && adapter->hw.speed == 10 * 1000) {
+			adapter->fw_sfp_10g_1g_auto_det =
+				(strcmp(value, "on") == 0) ? true : false;
+		} else {
+			adapter->fw_sfp_10g_1g_auto_det = false;
+		}
+	} else if (strcmp(key, RNP_FW_FORCE_SPEED_1G) == 0) {
+		adapter = (struct rnp_eth_adapter *)extra_args;
+		if (adapter->num_ports == 2) {
+			if (strcmp(value, "on") == 0)
+				adapter->fw_force_speed_1g = FOCE_SPEED_1G_ENABLED;
+			else if (strcmp(value, "off") == 0)
+				adapter->fw_force_speed_1g = FOCE_SPEED_1G_DISABLED;
+		}
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+rnp_parse_io_select_func(const char *key, const char *value, void *extra_args)
+{
+	uint8_t select = RNP_IO_FUNC_USE_NONE;
+
+	RTE_SET_USED(key);
+
+	if (strcmp(value, "vec") == 0)
+		select = RNP_IO_FUNC_USE_VEC;
+	else if (strcmp(value, "simple") == 0)
+		select = RNP_IO_FUNC_USE_SIMPLE;
+	else if (strcmp(value, "common") == 0)
+		select = RNP_IO_FUNC_USE_COMMON;
+
+	*(uint8_t *)extra_args = select;
+
+	return 0;
+}
+
+static int
+rnp_parse_devargs(struct rnp_eth_adapter *adapter,
+		  struct rte_devargs *devargs)
+{
+	uint8_t rx_io_func = RNP_IO_FUNC_USE_NONE;
+	uint8_t tx_io_func = RNP_IO_FUNC_USE_NONE;
+	struct rte_kvargs *kvlist;
+	bool loopback_en = false;
+	int ret = 0;
+
+	adapter->do_fw_update = false;
+	adapter->fw_sfp_10g_1g_auto_det = false;
+	adapter->fw_force_speed_1g = FOCE_SPEED_1G_NOT_SET;
+
+	if (!devargs)
+		goto def;
+
+	kvlist = rte_kvargs_parse(devargs->args, rnp_valid_arguments);
+	if (kvlist == NULL)
+		goto def;
+
+	if (rte_kvargs_count(kvlist, RNP_HW_MAC_LOOPBACK_ARG) == 1)
+		ret = rte_kvargs_process(kvlist, RNP_HW_MAC_LOOPBACK_ARG,
+				&rnp_parse_handle_devarg, &loopback_en);
+
+	if (rte_kvargs_count(kvlist, RNP_FW_4X10G_10G_1G_DET) == 1)
+		ret = rte_kvargs_process(kvlist,
+				RNP_FW_4X10G_10G_1G_DET,
+				&rnp_parse_handle_devarg,
+				adapter);
+
+	if (rte_kvargs_count(kvlist, RNP_FW_FORCE_SPEED_1G) == 1)
+		ret = rte_kvargs_process(kvlist,
+				RNP_FW_FORCE_SPEED_1G,
+				&rnp_parse_handle_devarg,
+				adapter);
+
+	if (rte_kvargs_count(kvlist, RNP_FW_UPDATE) == 1)
+		ret = rte_kvargs_process(kvlist, RNP_FW_UPDATE,
+				&rnp_parse_handle_devarg, adapter);
+	if (rte_kvargs_count(kvlist, RNP_RX_FUNC_SELECT) == 1)
+		ret = rte_kvargs_process(kvlist, RNP_RX_FUNC_SELECT,
+				&rnp_parse_io_select_func, &rx_io_func);
+	if (rte_kvargs_count(kvlist, RNP_TX_FUNC_SELECT) == 1)
+		ret = rte_kvargs_process(kvlist, RNP_TX_FUNC_SELECT,
+				&rnp_parse_io_select_func, &tx_io_func);
+	rte_kvargs_free(kvlist);
+def:
+	adapter->loopback_en = loopback_en;
+	adapter->rx_func_sec = rx_io_func;
+	adapter->tx_func_sec = tx_io_func;
+
+	return ret;
+}
+
+static int rnp_post_handle(struct rnp_eth_adapter *adapter)
+{
+	bool on = false;
+
+	if (!adapter->eth_dev)
+		return -ENOMEM;
+	if (adapter->do_fw_update && adapter->fw_path) {
+		rnp_fw_update(adapter);
+		adapter->do_fw_update = 0;
+	}
+
+	if (adapter->fw_sfp_10g_1g_auto_det)
+		return rnp_hw_set_fw_10g_1g_auto_detch(adapter->eth_dev, 1);
+
+	on = (adapter->fw_force_speed_1g == FOCE_SPEED_1G_ENABLED) ? 1 : 0;
+	if (adapter->fw_force_speed_1g != FOCE_SPEED_1G_NOT_SET)
+		return rnp_hw_set_fw_force_speed_1g(adapter->eth_dev, on);
+
+	return 0;
+}
+
 static int
 rnp_eth_dev_init(struct rte_eth_dev *dev)
 {
@@ -492,6 +650,11 @@ rnp_eth_dev_init(struct rte_eth_dev *dev)
 	/* We need Use Device Id To Change The Resource Mode */
 	rnp_special_ops_init(dev);
 	port->hw = hw;
+	ret = rnp_parse_devargs(adapter, pci_dev->device.devargs);
+	if (ret) {
+		PMD_DRV_LOG(ERR, "parse_devargs failed");
+		return ret;
+	}
 	for (p_id = 0; p_id < adapter->num_ports; p_id++) {
 		/* port 0 resource has been alloced When Probe */
 		if (!p_id) {
@@ -517,6 +680,9 @@ rnp_eth_dev_init(struct rte_eth_dev *dev)
 		rnp_mac_rx_disable(eth_dev);
 		rnp_mac_tx_disable(eth_dev);
 	}
+	ret = rnp_post_handle(adapter);
+	if (ret)
+		goto eth_alloc_error;
 
 	return 0;
 eth_alloc_error:
diff --git a/drivers/net/rnp/rnp_mbx_fw.c b/drivers/net/rnp/rnp_mbx_fw.c
index aea4f1d619..d98dd2dcd2 100644
--- a/drivers/net/rnp/rnp_mbx_fw.c
+++ b/drivers/net/rnp/rnp_mbx_fw.c
@@ -106,6 +106,27 @@ static int rnp_mbx_fw_post_req(struct rte_eth_dev *dev,
 	return err;
 }
 
+static int
+rnp_mbx_write_posted_locked(struct rte_eth_dev *dev, struct mbx_fw_cmd_req *req)
+{
+	const struct rnp_mbx_api *ops = RNP_DEV_TO_MBX_OPS(dev);
+	struct rnp_hw *hw = RNP_DEV_TO_HW(dev);
+	int err = 0;
+
+	rte_spinlock_lock(&hw->fw_lock);
+
+	err = ops->write_posted(dev, (u32 *)req,
+			(req->datalen + MBX_REQ_HDR_LEN) / 4, MBX_FW);
+	if (err) {
+		RNP_PMD_LOG(ERR, "%s failed!\n", __func__);
+		goto quit;
+	}
+
+quit:
+	rte_spinlock_unlock(&hw->fw_lock);
+	return err;
+}
+
 static int rnp_fw_get_capablity(struct rte_eth_dev *dev,
 				struct phy_abilities *abil)
 {
@@ -382,3 +403,146 @@ int rnp_mbx_get_lane_stat(struct rte_eth_dev *dev)
 quit:
 	return err;
 }
+
+static int rnp_maintain_req(struct rte_eth_dev *dev,
+		int cmd,
+		int arg0,
+		int req_data_bytes,
+		int reply_bytes,
+		phys_addr_t dma_phy_addr)
+{
+	struct rnp_hw *hw = RNP_DEV_TO_HW(dev);
+	struct mbx_req_cookie *cookie = NULL;
+	struct mbx_fw_cmd_req req;
+	int err;
+
+	if (!hw->mbx.irq_enabled)
+		return -EIO;
+	cookie = rnp_memzone_reserve(hw->cookie_p_name, 0);
+	if (!cookie)
+		return -ENOMEM;
+	memset(&req, 0, sizeof(req));
+	cookie->timeout_ms = 60 * 1000; /* 60s */
+
+	build_maintain_req(&req,
+			cookie,
+			cmd,
+			arg0,
+			req_data_bytes,
+			reply_bytes,
+			dma_phy_addr & 0xffffffff,
+			(dma_phy_addr >> 32) & 0xffffffff);
+
+	err = rnp_mbx_fw_post_req(dev, &req, cookie);
+
+	return (err) ? -EIO : 0;
+}
+
+int rnp_fw_update(struct rnp_eth_adapter *adapter)
+{
+	const struct rte_memzone *rz = NULL;
+	struct maintain_req *mt;
+	FILE *file;
+	int fsz;
+#define MAX_FW_BIN_SZ (552 * 1024)
+#define FW_256KB          (256 * 1024)
+
+	RNP_PMD_LOG(INFO, "%s: %s\n", __func__, adapter->fw_path);
+
+	file = fopen(adapter->fw_path, "rb");
+	if (!file) {
+		RNP_PMD_LOG(ERR,
+				"RNP: [%s] %s can't open for read\n",
+				__func__,
+				adapter->fw_path);
+		return -ENOENT;
+	}
+	/* get dma */
+	rz = rte_memzone_reserve("fw_update", MAX_FW_BIN_SZ, SOCKET_ID_ANY, 4);
+	if (rz == NULL) {
+		RNP_PMD_LOG(ERR, "RNP: [%s] not memory:%d\n", __func__,
+				MAX_FW_BIN_SZ);
+		return -EFBIG;
+	}
+	memset(rz->addr, 0xff, rz->len);
+	mt = (struct maintain_req *)rz->addr;
+
+	/* read data */
+	fsz = fread(mt->data, 1, rz->len, file);
+	if (fsz <= 0) {
+		RNP_PMD_LOG(INFO, "RNP: [%s] read failed! err:%d\n",
+				__func__, fsz);
+		return -EIO;
+	}
+	fclose(file);
+
+	if (fsz > ((256 + 4) * 1024)) {
+		printf("fw length:%d is two big. not supported!\n", fsz);
+		return -EINVAL;
+	}
+	RNP_PMD_LOG(NOTICE, "RNP: fw update ...\n");
+	fflush(stdout);
+
+	/* ==== update fw */
+	mt->magic       = MAINTAIN_MAGIC;
+	mt->cmd         = MT_WRITE_FLASH;
+	mt->arg0        = 1;
+	mt->req_data_bytes = (fsz > FW_256KB) ? FW_256KB : fsz;
+	mt->reply_bytes = 0;
+
+	if (rnp_maintain_req(adapter->eth_dev, mt->cmd, mt->arg0,
+				mt->req_data_bytes, mt->reply_bytes, rz->iova))
+		RNP_PMD_LOG(ERR, "maintain request failed!\n");
+	else
+		RNP_PMD_LOG(INFO, "maintail request done!\n");
+
+	/* ==== update cfg */
+	if (fsz > FW_256KB) {
+		mt->magic       = MAINTAIN_MAGIC;
+		mt->cmd         = MT_WRITE_FLASH;
+		mt->arg0        = 2;
+		mt->req_data_bytes = 4096;
+		mt->reply_bytes    = 0;
+		memcpy(mt->data, mt->data + FW_256KB, mt->req_data_bytes);
+
+		if (rnp_maintain_req(adapter->eth_dev,
+					mt->cmd, mt->arg0, mt->req_data_bytes,
+					mt->reply_bytes, rz->iova))
+			RNP_PMD_LOG(ERR, "maintain request failed!\n");
+		else
+			RNP_PMD_LOG(INFO, "maintail request done!\n");
+	}
+
+	RNP_PMD_LOG(NOTICE, "done\n");
+	fflush(stdout);
+
+	rte_memzone_free(rz);
+
+	exit(0);
+
+	return 0;
+}
+
+static int rnp_mbx_set_dump(struct rte_eth_dev *dev, int flag)
+{
+	struct rnp_eth_port *port = RNP_DEV_TO_PORT(dev);
+	struct mbx_fw_cmd_req req;
+	int err;
+
+	memset(&req, 0, sizeof(req));
+	build_set_dump(&req, port->attr.nr_lane, flag);
+
+	err = rnp_mbx_write_posted_locked(dev, &req);
+
+	return err;
+}
+
+int rnp_hw_set_fw_10g_1g_auto_detch(struct rte_eth_dev *dev, int enable)
+{
+	return rnp_mbx_set_dump(dev, 0x01140000 | (enable & 1));
+}
+
+int rnp_hw_set_fw_force_speed_1g(struct rte_eth_dev *dev, int enable)
+{
+	return rnp_mbx_set_dump(dev, 0x01150000 | (enable & 1));
+}
diff --git a/drivers/net/rnp/rnp_mbx_fw.h b/drivers/net/rnp/rnp_mbx_fw.h
index 7bf5c2a865..051ffd1bdc 100644
--- a/drivers/net/rnp/rnp_mbx_fw.h
+++ b/drivers/net/rnp/rnp_mbx_fw.h
@@ -16,6 +16,17 @@ struct mbx_req_cookie {
 	int priv_len;
 	char priv[RNP_MAX_SHARE_MEM];
 };
+struct maintain_req {
+	int magic;
+#define MAINTAIN_MAGIC 0xa6a7a8a9
+
+	int      cmd;
+	int      arg0;
+	int      req_data_bytes;
+	int      reply_bytes;
+	char data[0];
+} __rte_packed;
+
 enum GENERIC_CMD {
 	/* link configuration admin commands */
 	GET_PHY_ABALITY = 0x0601,
@@ -23,6 +34,9 @@ enum GENERIC_CMD {
 	RESET_PHY = 0x0603,
 	GET_LANE_STATUS = 0x0610,
 	SET_EVENT_MASK = 0x0613,
+	 /* fw update */
+	FW_MAINTAIN = 0x0701,
+	SET_DUMP = 0x0a10,
 };
 
 enum link_event_mask {
@@ -211,6 +225,21 @@ struct mbx_fw_cmd_req {
 		struct {
 			int nr_lane;
 		} get_lane_st;
+
+		struct {
+			int cmd;
+#define MT_WRITE_FLASH 1
+			int arg0;
+			int req_bytes;
+			int reply_bytes;
+			int ddr_lo;
+			int ddr_hi;
+		} maintain;
+
+		struct {
+			int flag;
+			int nr_lane;
+		} set_dump;
 	};
 } __rte_packed __rte_aligned(4);
 
@@ -284,6 +313,43 @@ build_get_lane_status_req(struct mbx_fw_cmd_req *req,
 	req->get_lane_st.nr_lane = nr_lane;
 }
 
+static inline void
+build_maintain_req(struct mbx_fw_cmd_req *req,
+		   void *cookie,
+		   int cmd,
+		   int arg0,
+		   int req_bytes,
+		   int reply_bytes,
+		   u32 dma_phy_lo,
+		   u32 dma_phy_hi)
+{
+	req->flags = 0;
+	req->opcode = FW_MAINTAIN;
+	req->datalen = sizeof(req->maintain);
+	req->cookie = cookie;
+	req->reply_lo = 0;
+	req->reply_hi = 0;
+	req->maintain.cmd = cmd;
+	req->maintain.arg0 = arg0;
+	req->maintain.req_bytes = req_bytes;
+	req->maintain.reply_bytes = reply_bytes;
+	req->maintain.ddr_lo = dma_phy_lo;
+	req->maintain.ddr_hi = dma_phy_hi;
+}
+
+static inline void
+build_set_dump(struct mbx_fw_cmd_req *req, int nr_lane, int flag)
+{
+	req->flags = 0;
+	req->opcode = SET_DUMP;
+	req->datalen = sizeof(req->set_dump);
+	req->cookie = NULL;
+	req->reply_lo = 0;
+	req->reply_hi = 0;
+	req->set_dump.flag = flag;
+	req->set_dump.nr_lane = nr_lane;
+}
+
 int rnp_mbx_get_capability(struct rte_eth_dev *dev,
 			   int *lane_mask,
 			   int *nic_mode);
@@ -295,4 +361,7 @@ rnp_fw_get_macaddr(struct rte_eth_dev *dev,
 		   u8 *mac_addr,
 		   int nr_lane);
 int rnp_mbx_get_lane_stat(struct rte_eth_dev *dev);
+int rnp_fw_update(struct rnp_eth_adapter *adapter);
+int rnp_hw_set_fw_10g_1g_auto_detch(struct rte_eth_dev *dev, int enable);
+int rnp_hw_set_fw_force_speed_1g(struct rte_eth_dev *dev, int enable);
 #endif /* __RNP_MBX_FW_H__*/
-- 
2.27.0


  parent reply	other threads:[~2023-08-03  7:53 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-03  7:52 [PATCH v3 0/8] [v3] drivers/net Add Support mucse N10 Pmd Driver Wenbo Cao
2023-08-03  7:52 ` [PATCH v3 1/8] net/rnp: add ethdev probe and remove Wenbo Cao
2023-08-03  7:52 ` [PATCH v3 2/8] " Wenbo Cao
2023-08-03  7:52 ` [PATCH v3 3/8] net/rnp: add device init and uninit Wenbo Cao
2023-08-03  7:52 ` [PATCH v3 4/8] net/rnp: add mbx basic api feature Wenbo Cao
2023-08-03  7:52 ` [PATCH v3 5/8] net/rnp add reset code for Chip Init process Wenbo Cao
2023-08-03  7:52 ` [PATCH v3 6/8] net/rnp add port info resource init Wenbo Cao
2023-08-03  7:52 ` Wenbo Cao [this message]
2023-08-03  7:52 ` [PATCH v3 8/8] net/rnp handle device interrupts Wenbo Cao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230803075233.3485076-8-caowenbo@mucse.com \
    --to=caowenbo@mucse.com \
    --cc=andrew.rybchenko@oktetlabs.ru \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@amd.com \
    --cc=stephen@networkplumber.org \
    --cc=yaojun@mucse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).