net/cnxk: support CPT CTX write through microcode op
[dpdk.git] / drivers / net / enic / enic_fm_flow.c
index 96ec360..2c60bb8 100644 (file)
@@ -5,7 +5,7 @@
 #include <errno.h>
 #include <stdint.h>
 #include <rte_log.h>
-#include <rte_ethdev_driver.h>
+#include <ethdev_driver.h>
 #include <rte_flow_driver.h>
 #include <rte_ether.h>
 #include <rte_hash.h>
@@ -368,8 +368,8 @@ enic_fm_copy_item_eth(struct copy_item_args *arg)
        fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
        fm_data->fk_header_select |= FKH_ETHER;
        fm_mask->fk_header_select |= FKH_ETHER;
-       memcpy(&fm_data->l2.eth, spec, sizeof(*spec));
-       memcpy(&fm_mask->l2.eth, mask, sizeof(*mask));
+       memcpy(&fm_data->l2.eth, spec, sizeof(struct rte_ether_hdr));
+       memcpy(&fm_mask->l2.eth, mask, sizeof(struct rte_ether_hdr));
        return 0;
 }
 
@@ -479,8 +479,8 @@ enic_fm_copy_item_ipv6(struct copy_item_args *arg)
 
        fm_data->fk_header_select |= FKH_IPV6;
        fm_mask->fk_header_select |= FKH_IPV6;
-       memcpy(&fm_data->l3.ip6, spec, sizeof(*spec));
-       memcpy(&fm_mask->l3.ip6, mask, sizeof(*mask));
+       memcpy(&fm_data->l3.ip6, spec, sizeof(struct rte_ipv6_hdr));
+       memcpy(&fm_mask->l3.ip6, mask, sizeof(struct rte_ipv6_hdr));
        return 0;
 }
 
@@ -1047,7 +1047,7 @@ enic_fm_copy_vxlan_encap(struct enic_flowman *fm,
        eth = (struct rte_ether_hdr *)template;
        ethertype = &eth->ether_type;
        append_template(&template, &off, item->spec,
-                       sizeof(struct rte_flow_item_eth));
+                       sizeof(struct rte_ether_hdr));
        item++;
        flow_item_skip_void(&item);
        /* Optional VLAN */
@@ -1242,6 +1242,35 @@ vf_egress_port_id_action(struct enic_flowman *fm,
        return 0;
 }
 
+static int
+enic_fm_check_transfer_dst(struct enic *enic, uint16_t dst_port_id,
+                          struct rte_eth_dev **dst_dev,
+                          struct rte_flow_error *error)
+{
+       struct rte_eth_dev *dev;
+
+       ENICPMD_LOG(DEBUG, "port id %u", dst_port_id);
+       if (!rte_eth_dev_is_valid_port(dst_port_id)) {
+               return rte_flow_error_set(error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ACTION,
+                       NULL, "invalid port_id");
+       }
+       dev = &rte_eth_devices[dst_port_id];
+       if (!dev_is_enic(dev)) {
+               return rte_flow_error_set(error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ACTION,
+                       NULL, "port_id is not enic");
+       }
+       if (enic->switch_domain_id != pmd_priv(dev)->switch_domain_id) {
+               return rte_flow_error_set(error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ACTION,
+                       NULL, "destination and source ports are not in the same switch domain");
+       }
+
+       *dst_dev = dev;
+       return 0;
+}
+
 /* Translate flow actions to flowman TCAM entry actions */
 static int
 enic_fm_copy_action(struct enic_flowman *fm,
@@ -1314,6 +1343,8 @@ enic_fm_copy_action(struct enic_flowman *fm,
                        const struct rte_flow_action_mark *mark =
                                actions->conf;
 
+                       if (enic->use_noscatter_vec_rx_handler)
+                               goto unsupported;
                        if (mark->id >= ENIC_MAGIC_FILTER_ID - 1)
                                return rte_flow_error_set(error, EINVAL,
                                        RTE_FLOW_ERROR_TYPE_ACTION,
@@ -1327,6 +1358,8 @@ enic_fm_copy_action(struct enic_flowman *fm,
                        break;
                }
                case RTE_FLOW_ACTION_TYPE_FLAG: {
+                       if (enic->use_noscatter_vec_rx_handler)
+                               goto unsupported;
                        /* ENIC_MAGIC_FILTER_ID is reserved for flagging */
                        memset(&fm_op, 0, sizeof(fm_op));
                        fm_op.fa_op = FMOP_MARK;
@@ -1431,7 +1464,7 @@ enic_fm_copy_action(struct enic_flowman *fm,
                }
                case RTE_FLOW_ACTION_TYPE_PORT_ID: {
                        const struct rte_flow_action_port_id *port;
-                       struct rte_eth_dev *dev;
+                       struct rte_eth_dev *dev = NULL;
 
                        if (!ingress && (overlap & PORT_ID)) {
                                ENICPMD_LOG(DEBUG, "cannot have multiple egress PORT_ID actions");
@@ -1442,24 +1475,10 @@ enic_fm_copy_action(struct enic_flowman *fm,
                                vnic_h = enic->fm_vnic_handle; /* This port */
                                break;
                        }
-                       ENICPMD_LOG(DEBUG, "port id %u", port->id);
-                       if (!rte_eth_dev_is_valid_port(port->id)) {
-                               return rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ACTION,
-                                       NULL, "invalid port_id");
-                       }
-                       dev = &rte_eth_devices[port->id];
-                       if (!dev_is_enic(dev)) {
-                               return rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ACTION,
-                                       NULL, "port_id is not enic");
-                       }
-                       if (enic->switch_domain_id !=
-                           pmd_priv(dev)->switch_domain_id) {
-                               return rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ACTION,
-                                       NULL, "destination and source ports are not in the same switch domain");
-                       }
+                       ret = enic_fm_check_transfer_dst(enic, port->id, &dev,
+                                                        error);
+                       if (ret)
+                               return ret;
                        vnic_h = pmd_priv(dev)->fm_vnic_handle;
                        overlap |= PORT_ID;
                        /*
@@ -1556,6 +1575,48 @@ enic_fm_copy_action(struct enic_flowman *fm,
                        ovlan |= rte_be_to_cpu_16(vid->vlan_vid);
                        break;
                }
+               case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR: {
+                       const struct rte_flow_action_ethdev *ethdev;
+                       struct rte_eth_dev *dev = NULL;
+
+                       ethdev = actions->conf;
+                       ret = enic_fm_check_transfer_dst(enic, ethdev->port_id,
+                                                        &dev, error);
+                       if (ret)
+                               return ret;
+                       vnic_h = pmd_priv(dev)->fm_vnic_handle;
+                       overlap |= PORT_ID;
+                       /*
+                        * Action PORT_REPRESENTOR implies ingress destination.
+                        * Noting to do. We add an implicit stree at the
+                        * end if needed.
+                        */
+                       ingress = 1;
+                       break;
+               }
+               case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: {
+                       const struct rte_flow_action_ethdev *ethdev;
+                       struct rte_eth_dev *dev = NULL;
+
+                       if (overlap & PORT_ID) {
+                               ENICPMD_LOG(DEBUG, "cannot have multiple egress PORT_ID actions");
+                               goto unsupported;
+                       }
+                       ethdev = actions->conf;
+                       ret = enic_fm_check_transfer_dst(enic, ethdev->port_id,
+                                                        &dev, error);
+                       if (ret)
+                               return ret;
+                       vnic_h = pmd_priv(dev)->fm_vnic_handle;
+                       overlap |= PORT_ID;
+                       /* Action REPRESENTED_PORT: always egress destination */
+                       ingress = 0;
+                       ret = vf_egress_port_id_action(fm, dev, vnic_h, &fm_op,
+                               error);
+                       if (ret)
+                               return ret;
+                       break;
+               }
                default:
                        goto unsupported;
                }
@@ -2232,7 +2293,11 @@ enic_action_handle_get(struct enic_flowman *fm, struct fm_action *action_in,
 error_with_action_handle:
        args[0] = FM_ACTION_FREE;
        args[1] = ah->handle;
-       flowman_cmd(fm, args, 2);
+       ret = flowman_cmd(fm, args, 2);
+       if (ret != 0)
+               rte_flow_error_set(error, -ret,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                  NULL, "enic: devcmd(action-free)");
 error_with_ah:
        free(ah);
        return ret;
@@ -2882,7 +2947,7 @@ enic_fm_init(struct enic *enic)
        rc = enic_fm_init_actions(fm);
        if (rc) {
                ENICPMD_LOG(ERR, "cannot create action hash, error:%d", rc);
-               goto error_tables;
+               goto error_counters;
        }
        /*
         * One default exact match table for each direction. We hold onto
@@ -2891,7 +2956,7 @@ enic_fm_init(struct enic *enic)
        rc = enic_fet_alloc(fm, 1, NULL, 128, &fm->default_ig_fet);
        if (rc) {
                ENICPMD_LOG(ERR, "cannot alloc default IG exact match table");
-               goto error_counters;
+               goto error_actions;
        }
        fm->default_ig_fet->ref = 1;
        rc = enic_fet_alloc(fm, 0, NULL, 128, &fm->default_eg_fet);
@@ -2906,6 +2971,8 @@ enic_fm_init(struct enic *enic)
 
 error_ig_fet:
        enic_fet_free(fm, fm->default_ig_fet);
+error_actions:
+       rte_hash_free(fm->action_hash);
 error_counters:
        enic_fm_free_all_counters(fm);
 error_tables: