[v7] net/i40e: i40e get link status update from ipn3ke

Message ID 1562827163-199199-1-git-send-email-andy.pei@intel.com
State Changes Requested, archived
Delegated to: Qi Zhang
Headers show
Series
  • [v7] net/i40e: i40e get link status update from ipn3ke
Related show

Checks

Context Check Description
ci/Intel-compilation success Compilation OK
ci/intel-Performance-Testing success Performance Testing PASS
ci/mellanox-Performance-Testing success Performance Testing PASS
ci/checkpatch success coding style OK

Commit Message

Andy Pei July 11, 2019, 6:39 a.m.
Add switch_mode argument for i40e PF to specify the specific FPGA that
i40e PF is connected to. i40e PF get link status update via the
connected FPGA.
Add bool switch_ethdev_support_flag to struct i40e_pf to specify if
there are switch_mode argues in cmd.
Add switch_ethdev to struct i40e_pf to track the bind switch device.
Try to bind i40e pf to switch device when i40e device is initialized.
If it fail to find correct switch device, bind will occur again when
update i40e device link status.

Signed-off-by: Andy Pei <andy.pei@intel.com>
---
Cc: qi.z.zhang@intel.com
Cc: jingjing.wu@intel.com
Cc: beilei.xing@intel.com
Cc: ferruh.yigit@intel.com
Cc: rosen.xu@intel.com
Cc: xiaolong.ye@intel.com
Cc: roy.fan.zhang@intel.com
Cc: stable@dpdk.org

v7:
* simplify code and delete redundance.

v6:
* fix some coding style.

v5:
* use a bool switch_ethdev_support_flag in struct i40e_pf to specify
* if i40e device needs to get link status update from ipn3ke device.

v4:
* use an array instead of a pointer to store switch device string to
* avoid memory free error.

v3:
* Add switch_ethdev to rte_eth_dev_data to track the bind switch
* device
* Try to bind i40e pf when it is probed.

v2:
* use a more specific subject for this patch.
* delete modifications that are not relevant.
* free memory allocted by strdup.
* delete unnecessary initializations.
* name function more precisely.
* wrap relevant code to a function to avoid too many levels of block
* nesting.

 doc/guides/nics/i40e.rst       |  11 +++
 drivers/net/i40e/i40e_ethdev.c | 166 ++++++++++++++++++++++++++++++++++++++++-
 drivers/net/i40e/i40e_ethdev.h |   6 ++
 3 files changed, 182 insertions(+), 1 deletion(-)

Comments

Zhang, Qi Z July 11, 2019, 8:45 a.m. | #1
> -----Original Message-----
> From: Pei, Andy
> Sent: Thursday, July 11, 2019 2:39 PM
> To: dev@dpdk.org
> Cc: Pei, Andy <andy.pei@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Wu,
> Jingjing <jingjing.wu@intel.com>; Xing, Beilei <beilei.xing@intel.com>; Yigit,
> Ferruh <ferruh.yigit@intel.com>; Xu, Rosen <rosen.xu@intel.com>; Ye,
> Xiaolong <xiaolong.ye@intel.com>; Zhang, Roy Fan
> <roy.fan.zhang@intel.com>; stable@dpdk.org
> Subject: [PATCH v7] net/i40e: i40e get link status update from ipn3ke
> 
> Add switch_mode argument for i40e PF to specify the specific FPGA that i40e
> PF is connected to. i40e PF get link status update via the connected FPGA.
> Add bool switch_ethdev_support_flag to struct i40e_pf to specify if there are
> switch_mode argues in cmd.
> Add switch_ethdev to struct i40e_pf to track the bind switch device.
> Try to bind i40e pf to switch device when i40e device is initialized.
> If it fail to find correct switch device, bind will occur again when update i40e
> device link status.
> 
> Signed-off-by: Andy Pei <andy.pei@intel.com>
....
> +	/* An example of cfg_str is "IPN3KE_0@b3:00.0_0" */

My understanding, in above example you want to have

Swtich_name = "0|b3:00.0" and port_name = "0", right?

> +	if (!strncmp(cfg_str, "IPN3KE", strlen("IPN3KE"))) {
> +		p_src = cfg_str;
> +		PMD_DRV_LOG(DEBUG, "cfg_str is %s", cfg_str);
> +
> +		/* move over "IPN3KE" */
> +		while ((*p_src != '_') && (*p_src))
> +			p_src++;

p_src = strchr(p_src, '_') should do the same thing?

> +
> +		/* move over the first underline */
> +		p_src++;

What if *p_src == null ?, error handle needed.

> +
> +		p_dst = switch_name;
> +		while ((*p_src != '_') && (*p_src)) {
> +			if (*p_src == '@') {
> +				*p_dst++ = '|';

Are you replace '@' to '|"? why not define the expected argument as "IPN3KE_0|b3:00.0_0", so can simply do strncpy here.

> +				p_src++;
> +			} else {
> +				*p_dst++ = *p_src++;
> +			}
> +		}
> +		*p_dst = 0;
> +		PMD_DRV_LOG(DEBUG, "switch_name is %s", switch_name);
> +
> +		/* move over the second underline */
> +		p_src++;

Same as above, error handle.

> +
> +		p_dst = port_name;
> +		while (*p_src)
> +			*p_dst++ = *p_src++;
> +		*p_dst = 0;

Use strncpy.

...

Patch

diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst
index a97484c..8d88f0d 100644
--- a/doc/guides/nics/i40e.rst
+++ b/doc/guides/nics/i40e.rst
@@ -513,6 +513,17 @@  details please refer to :doc:`../testpmd_app_ug/index`.
    testpmd> set port (port_id) queue-region flush (on|off)
    testpmd> show port (port_id) queue-region
 
+Switch Mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The Intel® Ethernet 700 Series can be component of IPN3KE device, in which the
+Intel® Ethernet 700 Series is connected to other pci device. This pci device
+works as switch device via which the Intel® Ethernet 700 Series get link status
+from. For example: the Intel® Ethernet 700 Series 0000:b1:00.0 is connected to
+an IPN3KE device whose BDF is b3:00.0. In this case 0000:b1:00.0 use representor
+0 on b3:00.0.
+
+   ./x86_64-native-linuxapp-gcc/app/testpmd -c 0x3 -n 4 -w 0000:b1:00.0,switch_mode=IPN3KE_0@b3:00.0_0
+
 Limitations or Known issues
 ---------------------------
 
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2b9fc45..4b5f0bb 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -44,6 +44,7 @@ 
 #define ETH_I40E_SUPPORT_MULTI_DRIVER	"support-multi-driver"
 #define ETH_I40E_QUEUE_NUM_PER_VF_ARG	"queue-num-per-vf"
 #define ETH_I40E_USE_LATEST_VEC	"use-latest-supported-vec"
+#define ETH_I40E_SWITCH_MODE_ARG	"switch_mode"
 
 #define I40E_CLEAR_PXE_WAIT_MS     200
 
@@ -406,6 +407,7 @@  static int i40e_sw_tunnel_filter_insert(struct i40e_pf *pf,
 	ETH_I40E_SUPPORT_MULTI_DRIVER,
 	ETH_I40E_QUEUE_NUM_PER_VF_ARG,
 	ETH_I40E_USE_LATEST_VEC,
+	ETH_I40E_SWITCH_MODE_ARG,
 	NULL};
 
 static const struct rte_pci_id pci_id_i40e_map[] = {
@@ -1260,6 +1262,115 @@  static inline void i40e_config_automask(struct i40e_pf *pf)
 #define I40E_ALARM_INTERVAL 50000 /* us */
 
 static int
+i40e_pf_parse_switch_mode(const char *key __rte_unused,
+	const char *value, void *extra_args)
+{
+	if (!value || !extra_args)
+		return -EINVAL;
+
+	if (strlen(value) < RTE_ETH_NAME_MAX_LEN) {
+		rte_memcpy(extra_args, value, strlen(value) + 1);
+	} else {
+		PMD_DRV_LOG(ERR,
+			"switch_mode args should be less than %d characters",
+			RTE_ETH_NAME_MAX_LEN);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct rte_eth_dev *
+i40e_eth_dev_get_by_switch_mode_name(const char *cfg_str)
+{
+	char switch_name[RTE_ETH_NAME_MAX_LEN];
+	char port_name[RTE_ETH_NAME_MAX_LEN];
+	char switch_ethdev_name[RTE_ETH_NAME_MAX_LEN];
+	uint16_t port_id;
+	const char *p_src;
+	char *p_dst;
+	int ret;
+
+	/* An example of cfg_str is "IPN3KE_0@b3:00.0_0" */
+	if (!strncmp(cfg_str, "IPN3KE", strlen("IPN3KE"))) {
+		p_src = cfg_str;
+		PMD_DRV_LOG(DEBUG, "cfg_str is %s", cfg_str);
+
+		/* move over "IPN3KE" */
+		while ((*p_src != '_') && (*p_src))
+			p_src++;
+
+		/* move over the first underline */
+		p_src++;
+
+		p_dst = switch_name;
+		while ((*p_src != '_') && (*p_src)) {
+			if (*p_src == '@') {
+				*p_dst++ = '|';
+				p_src++;
+			} else {
+				*p_dst++ = *p_src++;
+			}
+		}
+		*p_dst = 0;
+		PMD_DRV_LOG(DEBUG, "switch_name is %s", switch_name);
+
+		/* move over the second underline */
+		p_src++;
+
+		p_dst = port_name;
+		while (*p_src)
+			*p_dst++ = *p_src++;
+		*p_dst = 0;
+		PMD_DRV_LOG(DEBUG, "port_name is %s", port_name);
+
+		snprintf(switch_ethdev_name, sizeof(switch_ethdev_name),
+			"net_%s_representor_%s", switch_name, port_name);
+		PMD_DRV_LOG(DEBUG, "switch_ethdev_name is %s",
+			switch_ethdev_name);
+
+		ret = rte_eth_dev_get_port_by_name(switch_ethdev_name,
+			&port_id);
+		if (!ret)
+			return &rte_eth_devices[port_id];
+	}
+
+	return NULL;
+}
+
+static void
+eth_i40e_pf_switch_dev_init(struct rte_eth_dev *dev)
+{
+	char switch_cfg_str[RTE_ETH_NAME_MAX_LEN];
+	struct rte_kvargs *kvlist = NULL;
+	struct rte_devargs *devargs;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+	pf->switch_ethdev_support_flag = 0;
+	pf->switch_ethdev = NULL;
+
+	devargs = pci_dev->device.devargs;
+	if (!devargs)
+		return;
+
+	kvlist = rte_kvargs_parse(devargs->args, valid_keys);
+	if (kvlist) {
+		if (rte_kvargs_count(kvlist, ETH_I40E_SWITCH_MODE_ARG) == 1) {
+			pf->switch_ethdev_support_flag = 1;
+
+			if (!rte_kvargs_process(kvlist,
+				ETH_I40E_SWITCH_MODE_ARG,
+				&i40e_pf_parse_switch_mode, switch_cfg_str)) {
+				pf->switch_ethdev =
+					i40e_eth_dev_get_by_switch_mode_name
+					(switch_cfg_str);
+			}
+		}
+		rte_kvargs_free(kvlist);
+	}
+}
+
+static int
 eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
 {
 	struct rte_pci_device *pci_dev;
@@ -1582,6 +1693,11 @@  static inline void i40e_config_automask(struct i40e_pf *pf)
 	memset(&pf->rss_info, 0,
 		sizeof(struct i40e_rte_flow_rss_conf));
 
+	/* parse the switch device from devargs, try to bind to the switch
+	 * device, if binding not succeed, bind again when i40e_dev_link_update
+	 */
+	eth_i40e_pf_switch_dev_init(dev);
+
 	/* reset all stats of the device, including pf and main vsi */
 	i40e_dev_stats_reset(dev);
 
@@ -2779,13 +2895,52 @@  void i40e_flex_payload_reg_set_default(struct i40e_hw *hw)
 	}
 }
 
+static void
+i40e_pf_linkstatus_get_from_switch_ethdev
+(struct rte_eth_dev *switch_ethdev, struct rte_eth_link *link)
+{
+	if (switch_ethdev) {
+		rte_eth_linkstatus_get(switch_ethdev, link);
+	} else {
+		link->link_autoneg = ETH_LINK_SPEED_FIXED;
+		link->link_duplex  = ETH_LINK_FULL_DUPLEX;
+		link->link_speed   = ETH_SPEED_NUM_25G;
+		link->link_status  = 0;
+	}
+}
+
+static struct rte_eth_dev *
+i40e_get_switch_ethdev_from_devargs(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist = NULL;
+	struct rte_eth_dev *switch_ethdev = NULL;
+	char switch_cfg_str[RTE_ETH_NAME_MAX_LEN];
+
+	kvlist = rte_kvargs_parse(devargs->args, valid_keys);
+	if (kvlist) {
+		if (rte_kvargs_count(kvlist, ETH_I40E_SWITCH_MODE_ARG) == 1) {
+			if (!rte_kvargs_process(kvlist,
+				ETH_I40E_SWITCH_MODE_ARG,
+				&i40e_pf_parse_switch_mode, switch_cfg_str)) {
+				switch_ethdev =
+					i40e_eth_dev_get_by_switch_mode_name
+					(switch_cfg_str);
+			}
+		}
+		rte_kvargs_free(kvlist);
+	}
+	return switch_ethdev;
+}
+
 int
 i40e_dev_link_update(struct rte_eth_dev *dev,
 		     int wait_to_complete)
 {
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct rte_eth_link link;
 	bool enable_lse = dev->data->dev_conf.intr_conf.lsc ? true : false;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
 	int ret;
 
 	memset(&link, 0, sizeof(link));
@@ -2800,6 +2955,14 @@  void i40e_flex_payload_reg_set_default(struct i40e_hw *hw)
 	else
 		update_link_aq(hw, &link, enable_lse, wait_to_complete);
 
+	if (pf->switch_ethdev_support_flag) {
+		if (!pf->switch_ethdev)
+			pf->switch_ethdev = i40e_get_switch_ethdev_from_devargs
+				(pci_dev->device.devargs);
+		i40e_pf_linkstatus_get_from_switch_ethdev(pf->switch_ethdev,
+			&link);
+	}
+
 	ret = rte_eth_linkstatus_set(dev, &link);
 	i40e_notify_all_vfs_link_status(dev);
 
@@ -12773,4 +12936,5 @@  struct i40e_customized_pctype*
 			      ETH_I40E_FLOATING_VEB_LIST_ARG "=<string>"
 			      ETH_I40E_QUEUE_NUM_PER_VF_ARG "=1|2|4|8|16"
 			      ETH_I40E_SUPPORT_MULTI_DRIVER "=1"
-			      ETH_I40E_USE_LATEST_VEC "=0|1");
+			      ETH_I40E_USE_LATEST_VEC "=0|1"
+			      ETH_I40E_SWITCH_MODE_ARG "=IPN3KE");
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 38ac3ea..cfdcecb 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -975,6 +975,12 @@  struct i40e_pf {
 	struct i40e_customized_pctype customized_pctype[I40E_CUSTOMIZED_MAX];
 	/* Switch Domain Id */
 	uint16_t switch_domain_id;
+
+	/* flag indicating if switch mode is required like other devargs */
+	bool switch_ethdev_support_flag;
+
+	/* point to switch_ethdev specific by "switch_mode" in devargs */
+	struct rte_eth_dev *switch_ethdev;
 };
 
 enum pending_msg {