Merge branch 'sg_nents' into rdma.git for-next
[platform/kernel/linux-rpi.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index d4b0f27..160c7c3 100644 (file)
@@ -83,17 +83,17 @@ struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
        [CHAIN_TO_REG] = {
                .mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_0,
                .moffset = 0,
-               .mlen = 2,
+               .mlen = 16,
        },
        [VPORT_TO_REG] = {
                .mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_0,
-               .moffset = 2,
-               .mlen = 2,
+               .moffset = 16,
+               .mlen = 16,
        },
        [TUNNEL_TO_REG] = {
                .mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_1,
-               .moffset = 1,
-               .mlen = ((ESW_TUN_OPTS_BITS + ESW_TUN_ID_BITS) / 8),
+               .moffset = 8,
+               .mlen = ESW_TUN_OPTS_BITS + ESW_TUN_ID_BITS,
                .soffset = MLX5_BYTE_OFF(fte_match_param,
                                         misc_parameters_2.metadata_reg_c_1),
        },
@@ -110,7 +110,7 @@ struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
        [NIC_CHAIN_TO_REG] = {
                .mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_B,
                .moffset = 0,
-               .mlen = 2,
+               .mlen = 16,
        },
        [NIC_ZONE_RESTORE_TO_REG] = nic_zone_restore_to_reg_ct,
 };
@@ -128,23 +128,46 @@ static void mlx5e_put_flow_tunnel_id(struct mlx5e_tc_flow *flow);
 void
 mlx5e_tc_match_to_reg_match(struct mlx5_flow_spec *spec,
                            enum mlx5e_tc_attr_to_reg type,
-                           u32 data,
+                           u32 val,
                            u32 mask)
 {
+       void *headers_c = spec->match_criteria, *headers_v = spec->match_value, *fmask, *fval;
        int soffset = mlx5e_tc_attr_to_reg_mappings[type].soffset;
+       int moffset = mlx5e_tc_attr_to_reg_mappings[type].moffset;
        int match_len = mlx5e_tc_attr_to_reg_mappings[type].mlen;
-       void *headers_c = spec->match_criteria;
-       void *headers_v = spec->match_value;
-       void *fmask, *fval;
+       u32 max_mask = GENMASK(match_len - 1, 0);
+       __be32 curr_mask_be, curr_val_be;
+       u32 curr_mask, curr_val;
 
        fmask = headers_c + soffset;
        fval = headers_v + soffset;
 
-       mask = (__force u32)(cpu_to_be32(mask)) >> (32 - (match_len * 8));
-       data = (__force u32)(cpu_to_be32(data)) >> (32 - (match_len * 8));
+       memcpy(&curr_mask_be, fmask, 4);
+       memcpy(&curr_val_be, fval, 4);
+
+       curr_mask = be32_to_cpu(curr_mask_be);
+       curr_val = be32_to_cpu(curr_val_be);
+
+       //move to correct offset
+       WARN_ON(mask > max_mask);
+       mask <<= moffset;
+       val <<= moffset;
+       max_mask <<= moffset;
+
+       //zero val and mask
+       curr_mask &= ~max_mask;
+       curr_val &= ~max_mask;
+
+       //add current to mask
+       curr_mask |= mask;
+       curr_val |= val;
+
+       //back to be32 and write
+       curr_mask_be = cpu_to_be32(curr_mask);
+       curr_val_be = cpu_to_be32(curr_val);
 
-       memcpy(fmask, &mask, match_len);
-       memcpy(fval, &data, match_len);
+       memcpy(fmask, &curr_mask_be, 4);
+       memcpy(fval, &curr_val_be, 4);
 
        spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
 }
@@ -152,23 +175,28 @@ mlx5e_tc_match_to_reg_match(struct mlx5_flow_spec *spec,
 void
 mlx5e_tc_match_to_reg_get_match(struct mlx5_flow_spec *spec,
                                enum mlx5e_tc_attr_to_reg type,
-                               u32 *data,
+                               u32 *val,
                                u32 *mask)
 {
+       void *headers_c = spec->match_criteria, *headers_v = spec->match_value, *fmask, *fval;
        int soffset = mlx5e_tc_attr_to_reg_mappings[type].soffset;
+       int moffset = mlx5e_tc_attr_to_reg_mappings[type].moffset;
        int match_len = mlx5e_tc_attr_to_reg_mappings[type].mlen;
-       void *headers_c = spec->match_criteria;
-       void *headers_v = spec->match_value;
-       void *fmask, *fval;
+       u32 max_mask = GENMASK(match_len - 1, 0);
+       __be32 curr_mask_be, curr_val_be;
+       u32 curr_mask, curr_val;
 
        fmask = headers_c + soffset;
        fval = headers_v + soffset;
 
-       memcpy(mask, fmask, match_len);
-       memcpy(data, fval, match_len);
+       memcpy(&curr_mask_be, fmask, 4);
+       memcpy(&curr_val_be, fval, 4);
+
+       curr_mask = be32_to_cpu(curr_mask_be);
+       curr_val = be32_to_cpu(curr_val_be);
 
-       *mask = be32_to_cpu((__force __be32)(*mask << (32 - (match_len * 8))));
-       *data = be32_to_cpu((__force __be32)(*data << (32 - (match_len * 8))));
+       *mask = (curr_mask >> moffset) & max_mask;
+       *val = (curr_val >> moffset) & max_mask;
 }
 
 int
@@ -192,13 +220,13 @@ mlx5e_tc_match_to_reg_set_and_get_id(struct mlx5_core_dev *mdev,
                 (mod_hdr_acts->num_actions * MLX5_MH_ACT_SZ);
 
        /* Firmware has 5bit length field and 0 means 32bits */
-       if (mlen == 4)
+       if (mlen == 32)
                mlen = 0;
 
        MLX5_SET(set_action_in, modact, action_type, MLX5_ACTION_TYPE_SET);
        MLX5_SET(set_action_in, modact, field, mfield);
-       MLX5_SET(set_action_in, modact, offset, moffset * 8);
-       MLX5_SET(set_action_in, modact, length, mlen * 8);
+       MLX5_SET(set_action_in, modact, offset, moffset);
+       MLX5_SET(set_action_in, modact, length, mlen);
        MLX5_SET(set_action_in, modact, data, data);
        err = mod_hdr_acts->num_actions;
        mod_hdr_acts->num_actions++;
@@ -296,13 +324,13 @@ void mlx5e_tc_match_to_reg_mod_hdr_change(struct mlx5_core_dev *mdev,
        modact = mod_hdr_acts->actions + (act_id * MLX5_MH_ACT_SZ);
 
        /* Firmware has 5bit length field and 0 means 32bits */
-       if (mlen == 4)
+       if (mlen == 32)
                mlen = 0;
 
        MLX5_SET(set_action_in, modact, action_type, MLX5_ACTION_TYPE_SET);
        MLX5_SET(set_action_in, modact, field, mfield);
-       MLX5_SET(set_action_in, modact, offset, moffset * 8);
-       MLX5_SET(set_action_in, modact, length, mlen * 8);
+       MLX5_SET(set_action_in, modact, offset, moffset);
+       MLX5_SET(set_action_in, modact, length, mlen);
        MLX5_SET(set_action_in, modact, data, data);
 }
 
@@ -424,12 +452,32 @@ 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 mlx5_core_dev *mdev;
        struct net_device *netdev;
        struct mlx5e_priv *priv;
 
-       netdev = __dev_get_by_index(net, ifindex);
+       netdev = dev_get_by_index(net, ifindex);
+       if (!netdev)
+               return ERR_PTR(-ENODEV);
+
        priv = netdev_priv(netdev);
-       return priv->mdev;
+       mdev = priv->mdev;
+       dev_put(netdev);
+
+       /* Mirred tc action holds a refcount on the ifindex net_device (see
+        * net/sched/act_mirred.c:tcf_mirred_get_dev). So, it's okay to continue using mdev
+        * after dev_put(netdev), while we're in the context of adding a tc flow.
+        *
+        * The mdev pointer corresponds to the peer/out net_device of a hairpin. It is then
+        * stored in a hairpin object, which exists until all flows, that refer to it, get
+        * removed.
+        *
+        * On the other hand, after a hairpin object has been created, the peer net_device may
+        * be removed/unbound while there are still some hairpin flows that are using it. This
+        * case is handled by mlx5e_tc_hairpin_update_dead_peer, which is hooked to
+        * NETDEV_UNREGISTER event of the peer net_device.
+        */
+       return mdev;
 }
 
 static int mlx5e_hairpin_create_transport(struct mlx5e_hairpin *hp)
@@ -638,6 +686,10 @@ mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params
 
        func_mdev = priv->mdev;
        peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+       if (IS_ERR(peer_mdev)) {
+               err = PTR_ERR(peer_mdev);
+               goto create_pair_err;
+       }
 
        pair = mlx5_core_hairpin_create(func_mdev, peer_mdev, params);
        if (IS_ERR(pair)) {
@@ -776,6 +828,11 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
        int err;
 
        peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+       if (IS_ERR(peer_mdev)) {
+               NL_SET_ERR_MSG_MOD(extack, "invalid ifindex of mirred device");
+               return PTR_ERR(peer_mdev);
+       }
+
        if (!MLX5_CAP_GEN(priv->mdev, hairpin) || !MLX5_CAP_GEN(peer_mdev, hairpin)) {
                NL_SET_ERR_MSG_MOD(extack, "hairpin is not supported");
                return -EOPNOTSUPP;
@@ -818,7 +875,7 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
                 hash_hairpin_info(peer_id, match_prio));
        mutex_unlock(&priv->fs.tc.hairpin_tbl_lock);
 
-       params.log_data_size = 15;
+       params.log_data_size = 16;
        params.log_data_size = min_t(u8, params.log_data_size,
                                     MLX5_CAP_GEN(priv->mdev, log_max_hairpin_wq_data_sz));
        params.log_data_size = max_t(u8, params.log_data_size,
@@ -4820,6 +4877,7 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
        struct mlx5_core_dev *dev = priv->mdev;
        struct mapping_ctx *chains_mapping;
        struct mlx5_chains_attr attr = {};
+       u64 mapping_id;
        int err;
 
        mlx5e_mod_hdr_tbl_init(&tc->mod_hdr);
@@ -4833,8 +4891,12 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
 
        lockdep_set_class(&tc->ht.mutex, &tc_ht_lock_key);
 
-       chains_mapping = mapping_create(sizeof(struct mlx5_mapped_obj),
-                                       MLX5E_TC_TABLE_CHAIN_TAG_MASK, true);
+       mapping_id = mlx5_query_nic_system_image_guid(dev);
+
+       chains_mapping = mapping_create_for_id(mapping_id, MAPPING_TYPE_CHAIN,
+                                              sizeof(struct mlx5_mapped_obj),
+                                              MLX5E_TC_TABLE_CHAIN_TAG_MASK, true);
+
        if (IS_ERR(chains_mapping)) {
                err = PTR_ERR(chains_mapping);
                goto err_mapping;
@@ -4923,6 +4985,7 @@ int mlx5e_tc_esw_init(struct rhashtable *tc_ht)
        struct mapping_ctx *mapping;
        struct mlx5_eswitch *esw;
        struct mlx5e_priv *priv;
+       u64 mapping_id;
        int err = 0;
 
        uplink_priv = container_of(tc_ht, struct mlx5_rep_uplink_priv, tc_ht);
@@ -4939,8 +5002,12 @@ int mlx5e_tc_esw_init(struct rhashtable *tc_ht)
        uplink_priv->esw_psample = mlx5_esw_sample_init(netdev_priv(priv->netdev));
 #endif
 
-       mapping = mapping_create(sizeof(struct tunnel_match_key),
-                                TUNNEL_INFO_BITS_MASK, true);
+       mapping_id = mlx5_query_nic_system_image_guid(esw->dev);
+
+       mapping = mapping_create_for_id(mapping_id, MAPPING_TYPE_TUNNEL,
+                                       sizeof(struct tunnel_match_key),
+                                       TUNNEL_INFO_BITS_MASK, true);
+
        if (IS_ERR(mapping)) {
                err = PTR_ERR(mapping);
                goto err_tun_mapping;
@@ -4948,7 +5015,8 @@ int mlx5e_tc_esw_init(struct rhashtable *tc_ht)
        uplink_priv->tunnel_mapping = mapping;
 
        /* 0xFFF is reserved for stack devices slow path table mark */
-       mapping = mapping_create(sz_enc_opts, ENC_OPTS_BITS_MASK - 1, true);
+       mapping = mapping_create_for_id(mapping_id, MAPPING_TYPE_TUNNEL_ENC_OPTS,
+                                       sz_enc_opts, ENC_OPTS_BITS_MASK - 1, true);
        if (IS_ERR(mapping)) {
                err = PTR_ERR(mapping);
                goto err_enc_opts_mapping;
@@ -5105,7 +5173,7 @@ bool mlx5e_tc_update_skb(struct mlx5_cqe64 *cqe,
 
                tc_skb_ext->chain = chain;
 
-               zone_restore_id = (reg_b >> REG_MAPPING_SHIFT(NIC_ZONE_RESTORE_TO_REG)) &
+               zone_restore_id = (reg_b >> REG_MAPPING_MOFFSET(NIC_ZONE_RESTORE_TO_REG)) &
                        ESW_ZONE_ID_MASK;
 
                if (!mlx5e_tc_ct_restore_flow(tc->ct, skb,