[dpdk-dev] [PATCH v3] net/i40e: i40e get link status update from ipn3ke

Andy Pei andy.pei at intel.com
Thu Jul 4 08:56:07 CEST 2019


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 switch_ethdev to rte_eth_dev_data to track the bind switch device.
Try to bind i40e pf to switch device when i40e device is probed. 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 at intel.com>
---
Cc: qi.z.zhang at intel.com
Cc: jingjing.wu at intel.com
Cc: beilei.xing at intel.com
Cc: ferruh.yigit at intel.com
Cc: rosen.xu at intel.com
Cc: xiaolong.ye at intel.com
Cc: roy.fan.zhang at intel.com
Cc: stable at dpdk.org

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.

 drivers/net/i40e/i40e_ethdev.c      | 136 +++++++++++++++++++++++++++++++++++-
 lib/librte_ethdev/rte_ethdev_core.h |   4 ++
 2 files changed, 138 insertions(+), 2 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2b9fc45..8b4541d 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[] = {
@@ -625,14 +627,115 @@ struct rte_i40e_xstats_name_off {
 		sizeof(rte_i40e_txq_prio_strings[0]))
 
 static int
+i40e_pf_parse_switch_mode(const char *key __rte_unused,
+	const char *value, void *extra_args)
+{
+	if (!value || !extra_args)
+		return -EINVAL;
+
+	*(char **)extra_args = strdup(value);
+
+	if (!*(char **)extra_args)
+		return -ENOMEM;
+
+	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 at 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 NULL;
+		else
+			return &rte_eth_devices[port_id];
+	} else
+		return NULL;
+}
+
+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 = NULL;
+
+	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_free(switch_cfg_str);
+			}
+		}
+		rte_kvargs_free(kvlist);
+	}
+	return switch_ethdev;
+}
+
+static int
 eth_i40e_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 	struct rte_pci_device *pci_dev)
 {
 	char name[RTE_ETH_NAME_MAX_LEN];
 	struct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };
+	struct rte_eth_dev *switch_ethdev = NULL;
 	int i, retval;
 
 	if (pci_dev->device.devargs) {
+		switch_ethdev = i40e_get_switch_ethdev_from_devargs(
+			pci_dev->device.devargs);
 		retval = rte_eth_devargs_parse(pci_dev->device.devargs->args,
 				&eth_da);
 		if (retval)
@@ -654,6 +757,8 @@ struct rte_i40e_xstats_name_off {
 	if (pf_ethdev == NULL)
 		return -ENODEV;
 
+	pf_ethdev->data->switch_ethdev = switch_ethdev;
+
 	for (i = 0; i < eth_da.nb_representor_ports; i++) {
 		struct i40e_vf_representor representor = {
 			.vf_id = eth_da.representor_ports[i],
@@ -687,7 +792,7 @@ static int eth_i40e_pci_remove(struct rte_pci_device *pci_dev)
 	if (!ethdev)
 		return -ENODEV;
 
-
+	ethdev->data->switch_ethdev = NULL;
 	if (ethdev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR)
 		return rte_eth_dev_destroy(ethdev, i40e_vf_representor_uninit);
 	else
@@ -2779,6 +2884,20 @@ 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;
+	}
+}
+
 int
 i40e_dev_link_update(struct rte_eth_dev *dev,
 		     int wait_to_complete)
@@ -2786,6 +2905,8 @@ void i40e_flex_payload_reg_set_default(struct i40e_hw *hw)
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(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);
+	struct rte_devargs *devargs;
 	int ret;
 
 	memset(&link, 0, sizeof(link));
@@ -2800,6 +2921,16 @@ void i40e_flex_payload_reg_set_default(struct i40e_hw *hw)
 	else
 		update_link_aq(hw, &link, enable_lse, wait_to_complete);
 
+	if (!dev->data->switch_ethdev) {
+		devargs = pci_dev->device.devargs;
+		if (devargs)
+			dev->data->switch_ethdev =
+				i40e_get_switch_ethdev_from_devargs(
+					pci_dev->device.devargs);
+	}
+	i40e_pf_linkstatus_get_from_switch_ethdev(dev->data->switch_ethdev,
+		&link);
+
 	ret = rte_eth_linkstatus_set(dev, &link);
 	i40e_notify_all_vfs_link_status(dev);
 
@@ -12773,4 +12904,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/lib/librte_ethdev/rte_ethdev_core.h b/lib/librte_ethdev/rte_ethdev_core.h
index 2922d5b..62adc5c 100644
--- a/lib/librte_ethdev/rte_ethdev_core.h
+++ b/lib/librte_ethdev/rte_ethdev_core.h
@@ -635,6 +635,10 @@ struct rte_eth_dev_data {
 			/**< Switch-specific identifier.
 			 *   Valid if RTE_ETH_DEV_REPRESENTOR in dev_flags.
 			 */
+	struct rte_eth_dev *switch_ethdev;
+			/* point to switch_ethdev specific by "switch_mode" in
+			 * devargs
+			 */
 } __rte_cache_aligned;
 
 /**
-- 
1.8.3.1



More information about the dev mailing list