This patch implements checking if Multiport E-Switch is enabled
on a given PCI device using Devlink Linux kernel interface.
This facility will be used in follow up commits, which add support
for such configuration to mlx5 PMD.

If mlx5_core Linux kernel module supports Multiport E-Switch,
then it can be configured through a Devlink boolean parameter
"esw_multiport". Checking the value of this parameter
is implemented in mlx5_nl_devlink_esw_multiport_get() function.
If such parameter does not exist, this function returns -EINVAL.

To manually check if mlx5_core kernel module supports "esw_multiport"
parameter, and check if Multiport E-Switch is enabled,
one can use the following command:

  # <pci-dbdf> should be substituted with PCI device address
  # in format <domain>:<bus>:<device>:<function>.
  $ devlink dev param show pci/0000:08:00.0 name esw_multiport
  pci/0000:08:00.0:
    name esw_multiport type driver-specific
      values:
        cmode runtime value true

If parameter is not supported, Devlink command fails with
"Invalid argument" error.

Signed-off-by: Dariusz Sosnowski <dsosnow...@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viachesl...@nvidia.com>
---
 drivers/common/mlx5/linux/mlx5_nl.c | 70 +++++++++++++++++++++++++++++
 drivers/common/mlx5/linux/mlx5_nl.h |  5 +++
 drivers/common/mlx5/version.map     |  2 +
 3 files changed, 77 insertions(+)

diff --git a/drivers/common/mlx5/linux/mlx5_nl.c 
b/drivers/common/mlx5/linux/mlx5_nl.c
index 33670bb5c8..28a1f56dba 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -1962,3 +1962,73 @@ mlx5_nl_read_events(int nlsk_fd, mlx5_nl_event_cb *cb, 
void *cb_arg)
        }
        return 0;
 }
+
+static int
+mlx5_nl_esw_multiport_cb(struct nlmsghdr *nh, void *arg)
+{
+
+       int ret = -EINVAL;
+       int *enable = arg;
+       struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
+       struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
+                                       NLMSG_ALIGN(sizeof(struct genlmsghdr)));
+
+       while (nla->nla_len && nla < tail) {
+               switch (nla->nla_type) {
+               /* Expected nested attributes case. */
+               case DEVLINK_ATTR_PARAM:
+               case DEVLINK_ATTR_PARAM_VALUES_LIST:
+               case DEVLINK_ATTR_PARAM_VALUE:
+                       ret = 0;
+                       nla += 1;
+                       break;
+               case DEVLINK_ATTR_PARAM_VALUE_DATA:
+                       *enable = 1;
+                       return 0;
+               default:
+                       nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len));
+               }
+       }
+       *enable = 0;
+       return ret;
+}
+
+#define NL_ESW_MULTIPORT_PARAM "esw_multiport"
+
+int
+mlx5_nl_devlink_esw_multiport_get(int nlsk_fd, int family_id, const char 
*pci_addr, int *enable)
+{
+       struct nlmsghdr *nlh;
+       struct genlmsghdr *genl;
+       uint32_t sn = MLX5_NL_SN_GENERATE;
+       int ret;
+       uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                   NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
+                   NLMSG_ALIGN(sizeof(struct nlattr)) * 4 +
+                   NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4];
+
+       memset(buf, 0, sizeof(buf));
+       nlh = (struct nlmsghdr *)buf;
+       nlh->nlmsg_len = sizeof(struct nlmsghdr);
+       nlh->nlmsg_type = family_id;
+       nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       genl = (struct genlmsghdr *)nl_msg_tail(nlh);
+       nlh->nlmsg_len += sizeof(struct genlmsghdr);
+       genl->cmd = DEVLINK_CMD_PARAM_GET;
+       genl->version = DEVLINK_GENL_VERSION;
+       nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
+       nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
+       nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME,
+                   NL_ESW_MULTIPORT_PARAM, sizeof(NL_ESW_MULTIPORT_PARAM));
+       ret = mlx5_nl_send(nlsk_fd, nlh, sn);
+       if (ret >= 0)
+               ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_esw_multiport_cb, 
enable);
+       if (ret < 0) {
+               DRV_LOG(DEBUG, "Failed to get Multiport E-Switch enable on 
device %s: %d.",
+                       pci_addr, ret);
+               return ret;
+       }
+       DRV_LOG(DEBUG, "Multiport E-Switch is %sabled for device \"%s\".",
+               *enable ? "en" : "dis", pci_addr);
+       return ret;
+}
diff --git a/drivers/common/mlx5/linux/mlx5_nl.h 
b/drivers/common/mlx5/linux/mlx5_nl.h
index db01d7323e..580de3b769 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.h
+++ b/drivers/common/mlx5/linux/mlx5_nl.h
@@ -71,6 +71,7 @@ __rte_internal
 uint32_t mlx5_nl_vlan_vmwa_create(struct mlx5_nl_vlan_vmwa_context *vmwa,
                                  uint32_t ifindex, uint16_t tag);
 
+__rte_internal
 int mlx5_nl_devlink_family_id_get(int nlsk_fd);
 int mlx5_nl_enable_roce_get(int nlsk_fd, int family_id, const char *pci_addr,
                            int *enable);
@@ -82,4 +83,8 @@ int mlx5_nl_read_events(int nlsk_fd, mlx5_nl_event_cb *cb, 
void *cb_arg);
 __rte_internal
 int mlx5_nl_parse_link_status_update(struct nlmsghdr *hdr, uint32_t *ifindex);
 
+__rte_internal
+int mlx5_nl_devlink_esw_multiport_get(int nlsk_fd, int family_id,
+                                     const char *pci_addr, int *enable);
+
 #endif /* RTE_PMD_MLX5_NL_H_ */
diff --git a/drivers/common/mlx5/version.map b/drivers/common/mlx5/version.map
index 0758ba76de..074eed46fd 100644
--- a/drivers/common/mlx5/version.map
+++ b/drivers/common/mlx5/version.map
@@ -125,6 +125,8 @@ INTERNAL {
        mlx5_mr_addr2mr_bh;
 
        mlx5_nl_allmulti; # WINDOWS_NO_EXPORT
+       mlx5_nl_devlink_esw_multiport_get; # WINDOWS_NO_EXPORT
+       mlx5_nl_devlink_family_id_get; # WINDOWS_NO_EXPORT
        mlx5_nl_ifindex; # WINDOWS_NO_EXPORT
        mlx5_nl_init; # WINDOWS_NO_EXPORT
        mlx5_nl_mac_addr_add; # WINDOWS_NO_EXPORT
-- 
2.25.1

Reply via email to