1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 
4 #include "en_tc.h"
5 #include "post_act.h"
6 #include "mlx5_core.h"
7 #include "fs_core.h"
8 
9 struct mlx5e_post_act {
10 	enum mlx5_flow_namespace_type ns_type;
11 	struct mlx5_fs_chains *chains;
12 	struct mlx5_flow_table *ft;
13 	struct mlx5e_priv *priv;
14 	struct xarray ids;
15 };
16 
17 struct mlx5e_post_act_handle {
18 	enum mlx5_flow_namespace_type ns_type;
19 	struct mlx5_flow_attr *attr;
20 	struct mlx5_flow_handle *rule;
21 	u32 id;
22 };
23 
24 #define MLX5_POST_ACTION_BITS (mlx5e_tc_attr_to_reg_mappings[FTEID_TO_REG].mlen)
25 #define MLX5_POST_ACTION_MAX GENMASK(MLX5_POST_ACTION_BITS - 1, 0)
26 #define MLX5_POST_ACTION_MASK MLX5_POST_ACTION_MAX
27 
28 struct mlx5e_post_act *
29 mlx5e_tc_post_act_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
30 		       enum mlx5_flow_namespace_type ns_type)
31 {
32 	enum fs_flow_table_type table_type = ns_type == MLX5_FLOW_NAMESPACE_FDB ?
33 					     FS_FT_FDB : FS_FT_NIC_RX;
34 	struct mlx5e_post_act *post_act;
35 	int err;
36 
37 	if (!MLX5_CAP_FLOWTABLE_TYPE(priv->mdev, ignore_flow_level, table_type)) {
38 		if (priv->mdev->coredev_type != MLX5_COREDEV_VF)
39 			mlx5_core_warn(priv->mdev, "firmware level support is missing\n");
40 		err = -EOPNOTSUPP;
41 		goto err_check;
42 	}
43 
44 	post_act = kzalloc(sizeof(*post_act), GFP_KERNEL);
45 	if (!post_act) {
46 		err = -ENOMEM;
47 		goto err_check;
48 	}
49 	post_act->ft = mlx5_chains_create_global_table(chains);
50 	if (IS_ERR(post_act->ft)) {
51 		err = PTR_ERR(post_act->ft);
52 		mlx5_core_warn(priv->mdev, "failed to create post action table, err: %d\n", err);
53 		goto err_ft;
54 	}
55 	post_act->chains = chains;
56 	post_act->ns_type = ns_type;
57 	post_act->priv = priv;
58 	xa_init_flags(&post_act->ids, XA_FLAGS_ALLOC1);
59 	return post_act;
60 
61 err_ft:
62 	kfree(post_act);
63 err_check:
64 	return ERR_PTR(err);
65 }
66 
67 void
68 mlx5e_tc_post_act_destroy(struct mlx5e_post_act *post_act)
69 {
70 	if (IS_ERR_OR_NULL(post_act))
71 		return;
72 
73 	xa_destroy(&post_act->ids);
74 	mlx5_chains_destroy_global_table(post_act->chains, post_act->ft);
75 	kfree(post_act);
76 }
77 
78 struct mlx5e_post_act_handle *
79 mlx5e_tc_post_act_add(struct mlx5e_post_act *post_act, struct mlx5_flow_attr *attr)
80 {
81 	u32 attr_sz = ns_to_attr_sz(post_act->ns_type);
82 	struct mlx5e_post_act_handle *handle = NULL;
83 	struct mlx5_flow_attr *post_attr = NULL;
84 	struct mlx5_flow_spec *spec = NULL;
85 	int err;
86 
87 	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
88 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
89 	post_attr = mlx5_alloc_flow_attr(post_act->ns_type);
90 	if (!handle || !spec || !post_attr) {
91 		kfree(post_attr);
92 		kvfree(spec);
93 		kfree(handle);
94 		return ERR_PTR(-ENOMEM);
95 	}
96 
97 	memcpy(post_attr, attr, attr_sz);
98 	post_attr->chain = 0;
99 	post_attr->prio = 0;
100 	post_attr->ft = post_act->ft;
101 	post_attr->inner_match_level = MLX5_MATCH_NONE;
102 	post_attr->outer_match_level = MLX5_MATCH_NONE;
103 	post_attr->action &= ~(MLX5_FLOW_CONTEXT_ACTION_DECAP);
104 
105 	handle->ns_type = post_act->ns_type;
106 	/* Splits were handled before post action */
107 	if (handle->ns_type == MLX5_FLOW_NAMESPACE_FDB)
108 		post_attr->esw_attr->split_count = 0;
109 
110 	err = xa_alloc(&post_act->ids, &handle->id, post_attr,
111 		       XA_LIMIT(1, MLX5_POST_ACTION_MAX), GFP_KERNEL);
112 	if (err)
113 		goto err_xarray;
114 
115 	/* Post action rule matches on fte_id and executes original rule's
116 	 * tc rule action
117 	 */
118 	mlx5e_tc_match_to_reg_match(spec, FTEID_TO_REG,
119 				    handle->id, MLX5_POST_ACTION_MASK);
120 
121 	handle->rule = mlx5_tc_rule_insert(post_act->priv, spec, post_attr);
122 	if (IS_ERR(handle->rule)) {
123 		err = PTR_ERR(handle->rule);
124 		netdev_warn(post_act->priv->netdev, "Failed to add post action rule");
125 		goto err_rule;
126 	}
127 	handle->attr = post_attr;
128 
129 	kvfree(spec);
130 	return handle;
131 
132 err_rule:
133 	xa_erase(&post_act->ids, handle->id);
134 err_xarray:
135 	kfree(post_attr);
136 	kvfree(spec);
137 	kfree(handle);
138 	return ERR_PTR(err);
139 }
140 
141 void
142 mlx5e_tc_post_act_del(struct mlx5e_post_act *post_act, struct mlx5e_post_act_handle *handle)
143 {
144 	mlx5_tc_rule_delete(post_act->priv, handle->rule, handle->attr);
145 	xa_erase(&post_act->ids, handle->id);
146 	kfree(handle->attr);
147 	kfree(handle);
148 }
149 
150 struct mlx5_flow_table *
151 mlx5e_tc_post_act_get_ft(struct mlx5e_post_act *post_act)
152 {
153 	return post_act->ft;
154 }
155 
156 /* Allocate a header modify action to write the post action handle fte id to a register. */
157 int
158 mlx5e_tc_post_act_set_handle(struct mlx5_core_dev *dev,
159 			     struct mlx5e_post_act_handle *handle,
160 			     struct mlx5e_tc_mod_hdr_acts *acts)
161 {
162 	return mlx5e_tc_match_to_reg_set(dev, acts, handle->ns_type, FTEID_TO_REG, handle->id);
163 }
164