net/mlx5e: Basic setup of hairpin object
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index 55979ec2e88a14f7123ad164769feefe9c730618..55a527bda2e5adec40a361819f27d944e096f881 100644 (file)
@@ -93,6 +93,14 @@ enum {
 #define MLX5E_TC_TABLE_NUM_GROUPS 4
 #define MLX5E_TC_TABLE_MAX_GROUP_SIZE (1 << 16)
 
+struct mlx5e_hairpin {
+       struct mlx5_hairpin *pair;
+
+       struct mlx5_core_dev *func_mdev;
+       u32 tdn;
+       u32 tirn;
+};
+
 struct mod_hdr_key {
        int num_actions;
        void *actions;
@@ -222,6 +230,95 @@ static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv,
        }
 }
 
+static
+struct mlx5_core_dev *mlx5e_hairpin_get_mdev(struct net *net, int ifindex)
+{
+       struct net_device *netdev;
+       struct mlx5e_priv *priv;
+
+       netdev = __dev_get_by_index(net, ifindex);
+       priv = netdev_priv(netdev);
+       return priv->mdev;
+}
+
+static int mlx5e_hairpin_create_transport(struct mlx5e_hairpin *hp)
+{
+       u32 in[MLX5_ST_SZ_DW(create_tir_in)] = {0};
+       void *tirc;
+       int err;
+
+       err = mlx5_core_alloc_transport_domain(hp->func_mdev, &hp->tdn);
+       if (err)
+               goto alloc_tdn_err;
+
+       tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
+
+       MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
+       MLX5_SET(tirc, tirc, inline_rqn, hp->pair->rqn);
+       MLX5_SET(tirc, tirc, transport_domain, hp->tdn);
+
+       err = mlx5_core_create_tir(hp->func_mdev, in, MLX5_ST_SZ_BYTES(create_tir_in), &hp->tirn);
+       if (err)
+               goto create_tir_err;
+
+       return 0;
+
+create_tir_err:
+       mlx5_core_dealloc_transport_domain(hp->func_mdev, hp->tdn);
+alloc_tdn_err:
+       return err;
+}
+
+static void mlx5e_hairpin_destroy_transport(struct mlx5e_hairpin *hp)
+{
+       mlx5_core_destroy_tir(hp->func_mdev, hp->tirn);
+       mlx5_core_dealloc_transport_domain(hp->func_mdev, hp->tdn);
+}
+
+static struct mlx5e_hairpin *
+mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params,
+                    int peer_ifindex)
+{
+       struct mlx5_core_dev *func_mdev, *peer_mdev;
+       struct mlx5e_hairpin *hp;
+       struct mlx5_hairpin *pair;
+       int err;
+
+       hp = kzalloc(sizeof(*hp), GFP_KERNEL);
+       if (!hp)
+               return ERR_PTR(-ENOMEM);
+
+       func_mdev = priv->mdev;
+       peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+
+       pair = mlx5_core_hairpin_create(func_mdev, peer_mdev, params);
+       if (IS_ERR(pair)) {
+               err = PTR_ERR(pair);
+               goto create_pair_err;
+       }
+       hp->pair = pair;
+       hp->func_mdev = func_mdev;
+
+       err = mlx5e_hairpin_create_transport(hp);
+       if (err)
+               goto create_transport_err;
+
+       return hp;
+
+create_transport_err:
+       mlx5_core_hairpin_destroy(hp->pair);
+create_pair_err:
+       kfree(hp);
+       return ERR_PTR(err);
+}
+
+static void mlx5e_hairpin_destroy(struct mlx5e_hairpin *hp)
+{
+       mlx5e_hairpin_destroy_transport(hp);
+       mlx5_core_hairpin_destroy(hp->pair);
+       kvfree(hp);
+}
+
 static struct mlx5_flow_handle *
 mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
                      struct mlx5e_tc_flow_parse_attr *parse_attr,
@@ -617,7 +714,8 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
                                                  FLOW_DISSECTOR_KEY_ENC_PORTS,
                                                  f->mask);
                struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-               struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw);
+               struct mlx5e_rep_priv *uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
+               struct net_device *up_dev = uplink_rpriv->netdev;
                struct mlx5e_priv *up_priv = netdev_priv(up_dev);
 
                /* Full udp dst port must be given */
@@ -1507,6 +1605,7 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
                                   int *out_ttl)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+       struct mlx5e_rep_priv *uplink_rpriv;
        struct rtable *rt;
        struct neighbour *n = NULL;
 
@@ -1520,9 +1619,10 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
 #else
        return -EOPNOTSUPP;
 #endif
+       uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
        /* if the egress device isn't on the same HW e-switch, we use the uplink */
        if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev))
-               *out_dev = mlx5_eswitch_get_uplink_netdev(esw);
+               *out_dev = uplink_rpriv->netdev;
        else
                *out_dev = rt->dst.dev;
 
@@ -1547,6 +1647,7 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
        struct dst_entry *dst;
 
 #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
+       struct mlx5e_rep_priv *uplink_rpriv;
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        int ret;
 
@@ -1557,9 +1658,10 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
 
        *out_ttl = ip6_dst_hoplimit(dst);
 
+       uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
        /* if the egress device isn't on the same HW e-switch, we use the uplink */
        if (!switchdev_port_same_parent_id(priv->netdev, dst->dev))
-               *out_dev = mlx5_eswitch_get_uplink_netdev(esw);
+               *out_dev = uplink_rpriv->netdev;
        else
                *out_dev = dst->dev;
 #else
@@ -1859,7 +1961,9 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
                              struct mlx5e_tc_flow *flow)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw);
+       struct mlx5e_rep_priv *uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw,
+                                                                          REP_ETH);
+       struct net_device *up_dev = uplink_rpriv->netdev;
        unsigned short family = ip_tunnel_info_af(tun_info);
        struct mlx5e_priv *up_priv = netdev_priv(up_dev);
        struct mlx5_esw_flow_attr *attr = flow->esw_attr;
@@ -1982,11 +2086,10 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                }
 
                if (is_tcf_mirred_egress_redirect(a)) {
-                       int ifindex = tcf_mirred_ifindex(a);
                        struct net_device *out_dev;
                        struct mlx5e_priv *out_priv;
 
-                       out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex);
+                       out_dev = tcf_mirred_dev(a);
 
                        if (switchdev_port_same_parent_id(priv->netdev,
                                                          out_dev)) {
@@ -1996,7 +2099,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                                rpriv = out_priv->ppriv;
                                attr->out_rep = rpriv->rep;
                        } else if (encap) {
-                               parse_attr->mirred_ifindex = ifindex;
+                               parse_attr->mirred_ifindex = out_dev->ifindex;
                                parse_attr->tun_info = *info;
                                attr->parse_attr = parse_attr;
                                attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP |