net/mlx5: check metadata registers availability
authorViacheslav Ovsiienko <viacheslavo@mellanox.com>
Thu, 7 Nov 2019 17:09:53 +0000 (17:09 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 11 Nov 2019 13:23:01 +0000 (14:23 +0100)
The metadata registers reg_c provide support for TAG and
SET_TAG features. Although there are 8 registers are available
on the current mlx5 devices, some of them can be reserved.
The availability should be queried by iterative trial-and-error
implemented by mlx5_flow_discover_mreg_c() routine.

If reg_c is available, it can be regarded inclusively that
the extensive metadata support is possible. E.g. metadata
register copy action, supporting 16 modify header actions
(instead of 8 by default) preserving register across
different domains (FDB and NIC) and so on.

Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
Signed-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
Acked-by: Matan Azrad <matan@mellanox.com>
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_ethdev.c
drivers/net/mlx5/mlx5_flow.c
drivers/net/mlx5/mlx5_flow.h
drivers/net/mlx5/mlx5_flow_dv.c
drivers/net/mlx5/mlx5_prm.h

index 102c6ab..d9c666d 100644 (file)
@@ -2341,6 +2341,17 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                goto error;
        }
        priv->config.flow_prio = err;
+       /* Query availibility of metadata reg_c's. */
+       err = mlx5_flow_discover_mreg_c(eth_dev);
+       if (err < 0) {
+               err = -err;
+               goto error;
+       }
+       if (!mlx5_flow_ext_mreg_supported(eth_dev)) {
+               DRV_LOG(DEBUG,
+                       "port %u extensive metadata register is not supported",
+                       eth_dev->data->port_id);
+       }
        return eth_dev;
 error:
        if (priv) {
index b56dae1..d154243 100644 (file)
@@ -37,6 +37,7 @@
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
 #include "mlx5_glue.h"
+#include "mlx5_prm.h"
 
 enum {
        PCI_VENDOR_ID_MELLANOX = 0x15b3,
@@ -254,6 +255,8 @@ struct mlx5_dev_config {
        } mprq; /* Configurations for Multi-Packet RQ. */
        int mps; /* Multi-packet send supported mode. */
        unsigned int flow_prio; /* Number of flow priorities. */
+       enum modify_reg flow_mreg_c[MLX5_MREG_C_NUM];
+       /* Availibility of mreg_c's. */
        unsigned int tso_max_payload_sz; /* Maximum TCP payload for TSO. */
        unsigned int ind_table_max_size; /* Maximum indirection table size. */
        unsigned int max_dump_files_num; /* Maximum dump files per queue. */
@@ -563,6 +566,10 @@ struct mlx5_flow_tbl_resource {
 
 #define MLX5_MAX_TABLES UINT16_MAX
 #define MLX5_HAIRPIN_TX_TABLE (UINT16_MAX - 1)
+/* Reserve the last two tables for metadata register copy. */
+#define MLX5_FLOW_MREG_ACT_TABLE_GROUP (MLX5_MAX_TABLES - 1)
+#define MLX5_FLOW_MREG_CP_TABLE_GROUP \
+       (MLX5_FLOW_MREG_ACT_TABLE_GROUP - 1)
 #define MLX5_MAX_TABLES_FDB UINT16_MAX
 
 #define MLX5_DBR_PAGE_SIZE 4096 /* Must be >= 512. */
@@ -788,7 +795,7 @@ int mlx5_set_link_up(struct rte_eth_dev *dev);
 int mlx5_is_removed(struct rte_eth_dev *dev);
 eth_tx_burst_t mlx5_select_tx_function(struct rte_eth_dev *dev);
 eth_rx_burst_t mlx5_select_rx_function(struct rte_eth_dev *dev);
-struct mlx5_priv *mlx5_port_to_eswitch_info(uint16_t port);
+struct mlx5_priv *mlx5_port_to_eswitch_info(uint16_t port, bool valid);
 struct mlx5_priv *mlx5_dev_to_eswitch_info(struct rte_eth_dev *dev);
 int mlx5_sysfs_switch_info(unsigned int ifindex,
                           struct mlx5_switch_info *info);
@@ -868,6 +875,8 @@ int mlx5_traffic_restart(struct rte_eth_dev *dev);
 
 /* mlx5_flow.c */
 
+int mlx5_flow_discover_mreg_c(struct rte_eth_dev *eth_dev);
+bool mlx5_flow_ext_mreg_supported(struct rte_eth_dev *dev);
 int mlx5_flow_discover_priorities(struct rte_eth_dev *dev);
 void mlx5_flow_print(struct rte_flow *flow);
 int mlx5_flow_validate(struct rte_eth_dev *dev,
index c2bed2f..2b7c867 100644 (file)
@@ -1793,6 +1793,10 @@ mlx5_is_removed(struct rte_eth_dev *dev)
  *
  * @param[in] port
  *   Device port id.
+ * @param[in] valid
+ *   Device port id is valid, skip check. This flag is useful
+ *   when trials are performed from probing and device is not
+ *   flagged as valid yet (in attaching process).
  * @param[out] es_domain_id
  *   E-Switch domain id.
  * @param[out] es_port_id
@@ -1803,7 +1807,7 @@ mlx5_is_removed(struct rte_eth_dev *dev)
  *   on success, NULL otherwise and rte_errno is set.
  */
 struct mlx5_priv *
-mlx5_port_to_eswitch_info(uint16_t port)
+mlx5_port_to_eswitch_info(uint16_t port, bool valid)
 {
        struct rte_eth_dev *dev;
        struct mlx5_priv *priv;
@@ -1812,7 +1816,7 @@ mlx5_port_to_eswitch_info(uint16_t port)
                rte_errno = EINVAL;
                return NULL;
        }
-       if (!rte_eth_dev_is_valid_port(port)) {
+       if (!valid && !rte_eth_dev_is_valid_port(port)) {
                rte_errno = ENODEV;
                return NULL;
        }
index 5898c96..d54537a 100644 (file)
@@ -372,6 +372,33 @@ static enum modify_reg flow_get_reg_id(struct rte_eth_dev *dev,
                                  NULL, "invalid feature name");
 }
 
+
+/**
+ * Check extensive flow metadata register support.
+ *
+ * @param dev
+ *   Pointer to rte_eth_dev structure.
+ *
+ * @return
+ *   True if device supports extensive flow metadata register, otherwise false.
+ */
+bool
+mlx5_flow_ext_mreg_supported(struct rte_eth_dev *dev)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_dev_config *config = &priv->config;
+
+       /*
+        * Having available reg_c can be regarded inclusively as supporting
+        * extensive flow metadata register, which could mean,
+        * - metadata register copy action by modify header.
+        * - 16 modify header actions is supported.
+        * - reg_c's are preserved across different domain (FDB and NIC) on
+        *   packet loopback by flow lookup miss.
+        */
+       return config->flow_mreg_c[2] != REG_NONE;
+}
+
 /**
  * Discover the maximum number of priority available.
  *
@@ -4051,3 +4078,74 @@ mlx5_flow_group_to_table(const struct rte_flow_attr *attributes, bool external,
        }
        return 0;
 }
+
+/**
+ * Discover availability of metadata reg_c's.
+ *
+ * Iteratively use test flows to check availability.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_flow_discover_mreg_c(struct rte_eth_dev *dev)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_dev_config *config = &priv->config;
+       enum modify_reg idx;
+       int n = 0;
+
+       /* reg_c[0] and reg_c[1] are reserved. */
+       config->flow_mreg_c[n++] = REG_C_0;
+       config->flow_mreg_c[n++] = REG_C_1;
+       /* Discover availability of other reg_c's. */
+       for (idx = REG_C_2; idx <= REG_C_7; ++idx) {
+               struct rte_flow_attr attr = {
+                       .group = MLX5_FLOW_MREG_CP_TABLE_GROUP,
+                       .priority = MLX5_FLOW_PRIO_RSVD,
+                       .ingress = 1,
+               };
+               struct rte_flow_item items[] = {
+                       [0] = {
+                               .type = RTE_FLOW_ITEM_TYPE_END,
+                       },
+               };
+               struct rte_flow_action actions[] = {
+                       [0] = {
+                               .type = MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,
+                               .conf = &(struct mlx5_flow_action_copy_mreg){
+                                       .src = REG_C_1,
+                                       .dst = idx,
+                               },
+                       },
+                       [1] = {
+                               .type = RTE_FLOW_ACTION_TYPE_JUMP,
+                               .conf = &(struct rte_flow_action_jump){
+                                       .group = MLX5_FLOW_MREG_ACT_TABLE_GROUP,
+                               },
+                       },
+                       [2] = {
+                               .type = RTE_FLOW_ACTION_TYPE_END,
+                       },
+               };
+               struct rte_flow *flow;
+               struct rte_flow_error error;
+
+               if (!config->dv_flow_en)
+                       break;
+               /* Create internal flow, validation skips copy action. */
+               flow = flow_list_create(dev, NULL, &attr, items,
+                                       actions, false, &error);
+               if (!flow)
+                       continue;
+               if (dev->data->dev_started || !flow_drv_apply(dev, flow, NULL))
+                       config->flow_mreg_c[n++] = idx;
+               flow_list_destroy(dev, NULL, flow);
+       }
+       for (; n < MLX5_MREG_C_NUM; ++n)
+               config->flow_mreg_c[n] = REG_NONE;
+       return 0;
+}
index 05fee83..ba43ad7 100644 (file)
 #include "mlx5.h"
 #include "mlx5_prm.h"
 
-enum modify_reg {
-       REG_A,
-       REG_B,
-       REG_C_0,
-       REG_C_1,
-       REG_C_2,
-       REG_C_3,
-       REG_C_4,
-       REG_C_5,
-       REG_C_6,
-       REG_C_7,
-};
-
 /* Private rte flow items. */
 enum mlx5_rte_flow_item_type {
        MLX5_RTE_FLOW_ITEM_TYPE_END = INT_MIN,
index 582f172..1c9f5f7 100644 (file)
@@ -832,6 +832,7 @@ flow_dv_convert_action_modify_tcp_ack
 }
 
 static enum mlx5_modification_field reg_to_field[] = {
+       [REG_NONE] = MLX5_MODI_OUT_NONE,
        [REG_A] = MLX5_MODI_META_DATA_REG_A,
        [REG_B] = MLX5_MODI_META_DATA_REG_B,
        [REG_C_0] = MLX5_MODI_META_REG_C_0,
@@ -1040,7 +1041,7 @@ flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
                return ret;
        if (!spec)
                return 0;
-       esw_priv = mlx5_port_to_eswitch_info(spec->id);
+       esw_priv = mlx5_port_to_eswitch_info(spec->id, false);
        if (!esw_priv)
                return rte_flow_error_set(error, rte_errno,
                                          RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
@@ -2697,7 +2698,7 @@ flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
                                          "failed to obtain E-Switch info");
        port_id = action->conf;
        port = port_id->original ? dev->data->port_id : port_id->id;
-       act_priv = mlx5_port_to_eswitch_info(port);
+       act_priv = mlx5_port_to_eswitch_info(port, false);
        if (!act_priv)
                return rte_flow_error_set
                                (error, rte_errno,
@@ -5119,7 +5120,7 @@ flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
 
        mask = pid_m ? pid_m->id : 0xffff;
        id = pid_v ? pid_v->id : dev->data->port_id;
-       priv = mlx5_port_to_eswitch_info(id);
+       priv = mlx5_port_to_eswitch_info(id, item == NULL);
        if (!priv)
                return -rte_errno;
        /* Translate to vport field or to metadata, depending on mode. */
@@ -5567,7 +5568,7 @@ flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
                        (const struct rte_flow_action_port_id *)action->conf;
 
        port = conf->original ? dev->data->port_id : conf->id;
-       priv = mlx5_port_to_eswitch_info(port);
+       priv = mlx5_port_to_eswitch_info(port, false);
        if (!priv)
                return rte_flow_error_set(error, -rte_errno,
                                          RTE_FLOW_ERROR_TYPE_ACTION,
index b9e53f5..c17ba66 100644 (file)
@@ -392,6 +392,7 @@ enum {
 
 /* The field of packet to be modified. */
 enum mlx5_modification_field {
+       MLX5_MODI_OUT_NONE = -1,
        MLX5_MODI_OUT_SMAC_47_16 = 1,
        MLX5_MODI_OUT_SMAC_15_0,
        MLX5_MODI_OUT_ETHERTYPE,
@@ -455,6 +456,23 @@ enum mlx5_modification_field {
        MLX5_MODI_IN_TCP_ACK_NUM = 0x5C,
 };
 
+/* Total number of metadata reg_c's. */
+#define MLX5_MREG_C_NUM (MLX5_MODI_META_REG_C_7 - MLX5_MODI_META_REG_C_0 + 1)
+
+enum modify_reg {
+       REG_NONE = 0,
+       REG_A,
+       REG_B,
+       REG_C_0,
+       REG_C_1,
+       REG_C_2,
+       REG_C_3,
+       REG_C_4,
+       REG_C_5,
+       REG_C_6,
+       REG_C_7,
+};
+
 /* Modification sub command. */
 struct mlx5_modification_cmd {
        union {