net/bnxt: fix link status when port is stopped
[dpdk.git] / drivers / net / mlx5 / mlx5_flow.c
index ab48c52..f5bdf66 100644 (file)
@@ -175,6 +175,9 @@ mlx5_nsh_proto_to_item_type(uint8_t proto_spec, uint8_t proto_mask)
        enum rte_flow_item_type type;
 
        switch (proto_mask & proto_spec) {
+       case 0:
+               type = RTE_FLOW_ITEM_TYPE_VOID;
+               break;
        case RTE_VXLAN_GPE_TYPE_IPV4:
                type = RTE_FLOW_ITEM_TYPE_IPV4;
                break;
@@ -196,13 +199,16 @@ mlx5_inet_proto_to_item_type(uint8_t proto_spec, uint8_t proto_mask)
        enum rte_flow_item_type type;
 
        switch (proto_mask & proto_spec) {
+       case 0:
+               type = RTE_FLOW_ITEM_TYPE_VOID;
+               break;
        case IPPROTO_UDP:
                type = RTE_FLOW_ITEM_TYPE_UDP;
                break;
        case IPPROTO_TCP:
                type = RTE_FLOW_ITEM_TYPE_TCP;
                break;
-       case IPPROTO_IP:
+       case IPPROTO_IPIP:
                type = RTE_FLOW_ITEM_TYPE_IPV4;
                break;
        case IPPROTO_IPV6:
@@ -221,6 +227,9 @@ mlx5_ethertype_to_item_type(rte_be16_t type_spec,
        enum rte_flow_item_type type;
 
        switch (rte_be_to_cpu_16(type_spec & type_mask)) {
+       case 0:
+               type = RTE_FLOW_ITEM_TYPE_VOID;
+               break;
        case RTE_ETHER_TYPE_TEB:
                type = is_tunnel ?
                       RTE_FLOW_ITEM_TYPE_ETH : RTE_FLOW_ITEM_TYPE_END;
@@ -1370,8 +1379,11 @@ flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
                return;
        for (i = 0; i != ind_tbl->queues_n; ++i) {
                int idx = ind_tbl->queues[i];
-               struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, idx);
+               struct mlx5_rxq_ctrl *rxq_ctrl;
 
+               if (mlx5_is_external_rxq(dev, idx))
+                       continue;
+               rxq_ctrl = mlx5_rxq_ctrl_get(dev, idx);
                MLX5_ASSERT(rxq_ctrl != NULL);
                if (rxq_ctrl == NULL)
                        continue;
@@ -1474,8 +1486,11 @@ flow_drv_rxq_flags_trim(struct rte_eth_dev *dev,
        MLX5_ASSERT(dev->data->dev_started);
        for (i = 0; i != ind_tbl->queues_n; ++i) {
                int idx = ind_tbl->queues[i];
-               struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, idx);
+               struct mlx5_rxq_ctrl *rxq_ctrl;
 
+               if (mlx5_is_external_rxq(dev, idx))
+                       continue;
+               rxq_ctrl = mlx5_rxq_ctrl_get(dev, idx);
                MLX5_ASSERT(rxq_ctrl != NULL);
                if (rxq_ctrl == NULL)
                        continue;
@@ -1743,6 +1758,12 @@ mlx5_flow_validate_action_queue(const struct rte_flow_action *action,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "can't have 2 fate actions in"
                                          " same flow");
+       if (attr->egress)
+               return rte_flow_error_set(error, ENOTSUP,
+                                         RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL,
+                                         "queue action not supported for egress.");
+       if (mlx5_is_external_rxq(dev, queue->index))
+               return 0;
        if (!priv->rxqs_n)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION_CONF,
@@ -1757,11 +1778,6 @@ mlx5_flow_validate_action_queue(const struct rte_flow_action *action,
                                          RTE_FLOW_ERROR_TYPE_ACTION_CONF,
                                          &queue->index,
                                          "queue is not configured");
-       if (attr->egress)
-               return rte_flow_error_set(error, ENOTSUP,
-                                         RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL,
-                                         "queue action not supported for "
-                                         "egress");
        return 0;
 }
 
@@ -1776,7 +1792,7 @@ mlx5_flow_validate_action_queue(const struct rte_flow_action *action,
  *   Size of the @p queues array.
  * @param[out] error
  *   On error, filled with a textual error description.
- * @param[out] queue
+ * @param[out] queue_idx
  *   On error, filled with an offending queue index in @p queues array.
  *
  * @return
@@ -1789,17 +1805,27 @@ mlx5_validate_rss_queues(struct rte_eth_dev *dev,
 {
        const struct mlx5_priv *priv = dev->data->dev_private;
        bool is_hairpin = false;
+       bool is_ext_rss = false;
        uint32_t i;
 
        for (i = 0; i != queues_n; ++i) {
-               struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev,
-                                                                  queues[i]);
+               struct mlx5_rxq_ctrl *rxq_ctrl;
 
+               if (mlx5_is_external_rxq(dev, queues[0])) {
+                       is_ext_rss = true;
+                       continue;
+               }
+               if (is_ext_rss) {
+                       *error = "Combining external and regular RSS queues is not supported";
+                       *queue_idx = i;
+                       return -ENOTSUP;
+               }
                if (queues[i] >= priv->rxqs_n) {
                        *error = "queue index out of range";
                        *queue_idx = i;
                        return -EINVAL;
                }
+               rxq_ctrl = mlx5_rxq_ctrl_get(dev, queues[i]);
                if (rxq_ctrl == NULL) {
                        *error =  "queue is not configured";
                        *queue_idx = i;
@@ -1894,7 +1920,7 @@ mlx5_validate_action_rss(struct rte_eth_dev *dev,
                                          RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
                                          "L4 partial RSS requested but L4 RSS"
                                          " type not specified");
-       if (!priv->rxqs_n)
+       if (!priv->rxqs_n && priv->ext_rxqs == NULL)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION_CONF,
                                          NULL, "No Rx queues configured");
@@ -5251,6 +5277,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
        uint32_t flow_id = 0;
        uint32_t flow_id_reversed = 0;
        uint8_t flow_id_bits = 0;
+       bool after_meter = false;
        int shift;
 
        /* Prepare the suffix subflow items. */
@@ -5317,6 +5344,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
                                tag_action = actions_pre++;
                                action_cur = actions_pre++;
                        }
+                       after_meter = true;
                        break;
                case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
                case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
@@ -5345,6 +5373,11 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
                                                MLX5_RTE_FLOW_ITEM_TYPE_VLAN;
                        }
                        break;
+               case RTE_FLOW_ACTION_TYPE_COUNT:
+                       if (fm->def_policy)
+                               action_cur = after_meter ?
+                                               actions_sfx++ : actions_pre++;
+                       break;
                default:
                        break;
                }
@@ -5763,7 +5796,7 @@ flow_check_match_action(const struct rte_flow_action actions[],
        return flag ? actions_n + 1 : 0;
 }
 
-#define SAMPLE_SUFFIX_ITEM 2
+#define SAMPLE_SUFFIX_ITEM 3
 
 /**
  * Split the sample flow.
@@ -5804,6 +5837,7 @@ flow_check_match_action(const struct rte_flow_action actions[],
 static int
 flow_sample_split_prep(struct rte_eth_dev *dev,
                       int add_tag,
+                      const struct rte_flow_item items[],
                       struct rte_flow_item sfx_items[],
                       const struct rte_flow_action actions[],
                       struct rte_flow_action actions_sfx[],
@@ -5820,8 +5854,9 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
        struct mlx5_rte_flow_item_tag *tag_mask;
        struct rte_flow_action_jump *jump_action;
        uint32_t tag_id = 0;
-       int index;
        int append_index = 0;
+       int set_tag_idx = -1;
+       int index;
        int ret;
 
        if (sample_action_pos < 0)
@@ -5830,6 +5865,52 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
                                          NULL, "invalid position of sample "
                                          "action in list");
        /* Prepare the actions for prefix and suffix flow. */
+       if (add_tag) {
+               /* Update the new added tag action index preceding
+                * the PUSH_VLAN or ENCAP action.
+                */
+               const struct rte_flow_action_raw_encap *raw_encap;
+               const struct rte_flow_action *action = actions;
+               int encap_idx;
+               int action_idx = 0;
+               int raw_decap_idx = -1;
+               int push_vlan_idx = -1;
+               for (; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
+                       switch (action->type) {
+                       case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+                               raw_decap_idx = action_idx;
+                               break;
+                       case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+                               raw_encap = action->conf;
+                               if (raw_encap->size >
+                                       MLX5_ENCAPSULATION_DECISION_SIZE) {
+                                       encap_idx = raw_decap_idx != -1 ?
+                                                   raw_decap_idx : action_idx;
+                                       if (encap_idx < sample_action_pos &&
+                                           push_vlan_idx == -1)
+                                               set_tag_idx = encap_idx;
+                               }
+                               break;
+                       case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+                       case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+                               encap_idx = action_idx;
+                               if (encap_idx < sample_action_pos &&
+                                   push_vlan_idx == -1)
+                                       set_tag_idx = encap_idx;
+                               break;
+                       case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+                       case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+                               push_vlan_idx = action_idx;
+                               if (push_vlan_idx < sample_action_pos)
+                                       set_tag_idx = action_idx;
+                               break;
+                       default:
+                               break;
+                       }
+                       action_idx++;
+               }
+       }
+       /* Prepare the actions for prefix and suffix flow. */
        if (qrss_action_pos >= 0 && qrss_action_pos < sample_action_pos) {
                index = qrss_action_pos;
                /* Put the preceding the Queue/RSS action into prefix flow. */
@@ -5846,6 +5927,14 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
                memcpy(actions_sfx, actions + qrss_action_pos,
                       sizeof(struct rte_flow_action));
                actions_sfx++;
+       } else if (add_tag && set_tag_idx >= 0) {
+               if (set_tag_idx > 0)
+                       memcpy(actions_pre, actions,
+                              sizeof(struct rte_flow_action) * set_tag_idx);
+               memcpy(actions_pre + set_tag_idx + 1, actions + set_tag_idx,
+                      sizeof(struct rte_flow_action) *
+                      (sample_action_pos - set_tag_idx));
+               index = sample_action_pos;
        } else {
                index = sample_action_pos;
                if (index != 0)
@@ -5861,6 +5950,12 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
                append_index++;
                set_tag = (void *)(actions_pre + actions_n + append_index);
                ret = mlx5_flow_get_reg_id(dev, MLX5_SAMPLE_ID, 0, error);
+               /* Trust VF/SF on CX5 not supported meter so that the reserved
+                * metadata regC is REG_NON, back to use application tag
+                * index 0.
+                */
+               if (unlikely(ret == REG_NON))
+                       ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 0, error);
                if (ret < 0)
                        return ret;
                mlx5_ipool_malloc(priv->sh->ipool
@@ -5870,6 +5965,12 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
                        .data = tag_id,
                };
                /* Prepare the suffix subflow items. */
+               for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
+                       if (items->type == RTE_FLOW_ITEM_TYPE_PORT_ID) {
+                               memcpy(sfx_items, items, sizeof(*sfx_items));
+                               sfx_items++;
+                       }
+               }
                tag_spec = (void *)(sfx_items + SAMPLE_SUFFIX_ITEM);
                tag_spec->data = tag_id;
                tag_spec->id = set_tag->id;
@@ -5887,13 +5988,17 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
                                RTE_FLOW_ITEM_TYPE_END,
                };
                /* Prepare the tag action in prefix subflow. */
-               actions_pre[index++] =
+               set_tag_idx = (set_tag_idx == -1) ? index : set_tag_idx;
+               actions_pre[set_tag_idx] =
                        (struct rte_flow_action){
                        .type = (enum rte_flow_action_type)
                                MLX5_RTE_FLOW_ACTION_TYPE_TAG,
                        .conf = set_tag,
                };
+               /* Update next sample position due to add one tag action */
+               index += 1;
        }
+       /* Copy the sample action into prefix flow. */
        memcpy(actions_pre + index, actions + sample_action_pos,
               sizeof(struct rte_flow_action));
        index += 1;
@@ -6276,6 +6381,8 @@ flow_create_split_meter(struct rte_eth_dev *dev,
                                                                  fm->policy_id,
                                                                  NULL);
                        MLX5_ASSERT(wks->policy);
+                       if (wks->policy->mark)
+                               wks->mark = 1;
                        if (wks->policy->is_hierarchy) {
                                wks->final_policy =
                                mlx5_flow_meter_hierarchy_get_final_policy(dev,
@@ -6299,8 +6406,10 @@ flow_create_split_meter(struct rte_eth_dev *dev,
                if (!fm->def_policy && !is_mtr_hierarchy &&
                    (!has_modify || !fm->drop_cnt))
                        set_mtr_reg = false;
-               /* Prefix actions: meter, decap, encap, tag, jump, end. */
-               act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
+               /* Prefix actions: meter, decap, encap, tag, jump, end, cnt. */
+#define METER_PREFIX_ACTION 7
+               act_size = (sizeof(struct rte_flow_action) *
+                           (actions_n + METER_PREFIX_ACTION)) +
                           sizeof(struct mlx5_rte_flow_action_set_tag);
                /* Suffix items: tag, vlan, port id, end. */
 #define METER_SUFFIX_ITEM 4
@@ -6476,7 +6585,7 @@ flow_create_split_sample(struct rte_eth_dev *dev,
                        jump_table = attr->group * MLX5_FLOW_TABLE_FACTOR +
                                     next_ft_step;
                pre_actions = sfx_actions + actions_n;
-               tag_id = flow_sample_split_prep(dev, add_tag, sfx_items,
+               tag_id = flow_sample_split_prep(dev, add_tag, items, sfx_items,
                                                actions, sfx_actions,
                                                pre_actions, actions_n,
                                                sample_action_pos,
@@ -10608,10 +10717,27 @@ mlx5_flow_flex_item_create(struct rte_eth_dev *dev,
                           struct rte_flow_error *error)
 {
        static const char err_msg[] = "flex item creation unsupported";
+       struct mlx5_priv *priv = dev->data->dev_private;
        struct rte_flow_attr attr = { .transfer = 0 };
        const struct mlx5_flow_driver_ops *fops =
                        flow_get_drv_ops(flow_get_drv_type(dev, &attr));
 
+       if (!priv->pci_dev) {
+               rte_flow_error_set(error, ENOTSUP,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                  "create flex item on PF only");
+               return NULL;
+       }
+       switch (priv->pci_dev->id.device_id) {
+       case PCI_DEVICE_ID_MELLANOX_CONNECTX6DXBF:
+       case PCI_DEVICE_ID_MELLANOX_CONNECTX7BF:
+               break;
+       default:
+               rte_flow_error_set(error, ENOTSUP,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                  "flex item available on BlueField ports only");
+               return NULL;
+       }
        if (!fops->item_create) {
                DRV_LOG(ERR, "port %u %s.", dev->data->port_id, err_msg);
                rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,