1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* Copyright (c) 2020 Mellanox Technologies */ |
3 | |
4 | #include "en/txrx.h" |
5 | #include "en/params.h" |
6 | #include "en/trap.h" |
7 | |
8 | static int mlx5e_trap_napi_poll(struct napi_struct *napi, int budget) |
9 | { |
10 | struct mlx5e_trap *trap_ctx = container_of(napi, struct mlx5e_trap, napi); |
11 | struct mlx5e_ch_stats *ch_stats = trap_ctx->stats; |
12 | struct mlx5e_rq *rq = &trap_ctx->rq; |
13 | bool busy = false; |
14 | int work_done = 0; |
15 | |
16 | rcu_read_lock(); |
17 | |
18 | ch_stats->poll++; |
19 | |
20 | work_done = mlx5e_poll_rx_cq(cq: &rq->cq, budget); |
21 | busy |= work_done == budget; |
22 | busy |= rq->post_wqes(rq); |
23 | |
24 | if (busy) { |
25 | work_done = budget; |
26 | goto out; |
27 | } |
28 | |
29 | if (unlikely(!napi_complete_done(napi, work_done))) |
30 | goto out; |
31 | |
32 | mlx5e_cq_arm(cq: &rq->cq); |
33 | |
34 | out: |
35 | rcu_read_unlock(); |
36 | return work_done; |
37 | } |
38 | |
39 | static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params, |
40 | struct mlx5e_rq *rq) |
41 | { |
42 | struct mlx5_core_dev *mdev = t->mdev; |
43 | struct mlx5e_priv *priv = t->priv; |
44 | |
45 | rq->wq_type = params->rq_wq_type; |
46 | rq->pdev = t->pdev; |
47 | rq->netdev = priv->netdev; |
48 | rq->priv = priv; |
49 | rq->clock = &mdev->clock; |
50 | rq->tstamp = &priv->tstamp; |
51 | rq->mdev = mdev; |
52 | rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu); |
53 | rq->stats = &priv->trap_stats.rq; |
54 | rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev); |
55 | xdp_rxq_info_unused(xdp_rxq: &rq->xdp_rxq); |
56 | mlx5e_rq_set_trap_handlers(rq, params); |
57 | } |
58 | |
59 | static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t) |
60 | { |
61 | struct mlx5e_rq_param *rq_param = &t->rq_param; |
62 | struct mlx5_core_dev *mdev = priv->mdev; |
63 | struct mlx5e_create_cq_param ccp = {}; |
64 | struct dim_cq_moder trap_moder = {}; |
65 | struct mlx5e_rq *rq = &t->rq; |
66 | u16 q_counter; |
67 | int node; |
68 | int err; |
69 | |
70 | node = dev_to_node(dev: mdev->device); |
71 | q_counter = priv->q_counter[0]; |
72 | |
73 | ccp.netdev = priv->netdev; |
74 | ccp.wq = priv->wq; |
75 | ccp.node = node; |
76 | ccp.ch_stats = t->stats; |
77 | ccp.napi = &t->napi; |
78 | ccp.ix = 0; |
79 | err = mlx5e_open_cq(mdev: priv->mdev, moder: trap_moder, param: &rq_param->cqp, ccp: &ccp, cq: &rq->cq); |
80 | if (err) |
81 | return err; |
82 | |
83 | mlx5e_init_trap_rq(t, params: &t->params, rq); |
84 | err = mlx5e_open_rq(params: &t->params, param: rq_param, NULL, node, q_counter, rq); |
85 | if (err) |
86 | goto err_destroy_cq; |
87 | |
88 | return 0; |
89 | |
90 | err_destroy_cq: |
91 | mlx5e_close_cq(cq: &rq->cq); |
92 | |
93 | return err; |
94 | } |
95 | |
96 | static void mlx5e_close_trap_rq(struct mlx5e_rq *rq) |
97 | { |
98 | mlx5e_close_rq(rq); |
99 | mlx5e_close_cq(cq: &rq->cq); |
100 | } |
101 | |
102 | static int mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir, |
103 | u32 rqn) |
104 | { |
105 | struct mlx5e_tir_builder *builder; |
106 | int err; |
107 | |
108 | builder = mlx5e_tir_builder_alloc(modify: false); |
109 | if (!builder) |
110 | return -ENOMEM; |
111 | |
112 | mlx5e_tir_builder_build_inline(builder, tdn: mdev->mlx5e_res.hw_objs.td.tdn, rqn); |
113 | err = mlx5e_tir_init(tir, builder, mdev, reg: true); |
114 | |
115 | mlx5e_tir_builder_free(builder); |
116 | |
117 | return err; |
118 | } |
119 | |
120 | static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev, |
121 | int max_mtu, struct mlx5e_trap *t) |
122 | { |
123 | struct mlx5e_params *params = &t->params; |
124 | |
125 | params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC; |
126 | mlx5e_init_rq_type_params(mdev, params); |
127 | params->sw_mtu = max_mtu; |
128 | mlx5e_build_rq_param(mdev, params, NULL, param: &t->rq_param); |
129 | } |
130 | |
131 | static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv) |
132 | { |
133 | int cpu = mlx5_comp_vector_get_cpu(dev: priv->mdev, vector: 0); |
134 | struct net_device *netdev = priv->netdev; |
135 | struct mlx5e_trap *t; |
136 | int err; |
137 | |
138 | t = kvzalloc_node(size: sizeof(*t), GFP_KERNEL, cpu_to_node(cpu)); |
139 | if (!t) |
140 | return ERR_PTR(error: -ENOMEM); |
141 | |
142 | mlx5e_build_trap_params(mdev: priv->mdev, max_mtu: netdev->max_mtu, t); |
143 | |
144 | t->priv = priv; |
145 | t->mdev = priv->mdev; |
146 | t->tstamp = &priv->tstamp; |
147 | t->pdev = mlx5_core_dma_dev(dev: priv->mdev); |
148 | t->netdev = priv->netdev; |
149 | t->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey); |
150 | t->stats = &priv->trap_stats.ch; |
151 | |
152 | netif_napi_add(dev: netdev, napi: &t->napi, poll: mlx5e_trap_napi_poll); |
153 | |
154 | err = mlx5e_open_trap_rq(priv, t); |
155 | if (unlikely(err)) |
156 | goto err_napi_del; |
157 | |
158 | err = mlx5e_create_trap_direct_rq_tir(mdev: t->mdev, tir: &t->tir, rqn: t->rq.rqn); |
159 | if (err) |
160 | goto err_close_trap_rq; |
161 | |
162 | return t; |
163 | |
164 | err_close_trap_rq: |
165 | mlx5e_close_trap_rq(rq: &t->rq); |
166 | err_napi_del: |
167 | netif_napi_del(napi: &t->napi); |
168 | kvfree(addr: t); |
169 | return ERR_PTR(error: err); |
170 | } |
171 | |
172 | void mlx5e_close_trap(struct mlx5e_trap *trap) |
173 | { |
174 | mlx5e_tir_destroy(tir: &trap->tir); |
175 | mlx5e_close_trap_rq(rq: &trap->rq); |
176 | netif_napi_del(napi: &trap->napi); |
177 | kvfree(addr: trap); |
178 | } |
179 | |
180 | static void mlx5e_activate_trap(struct mlx5e_trap *trap) |
181 | { |
182 | napi_enable(n: &trap->napi); |
183 | mlx5e_activate_rq(rq: &trap->rq); |
184 | mlx5e_trigger_napi_sched(napi: &trap->napi); |
185 | } |
186 | |
187 | void mlx5e_deactivate_trap(struct mlx5e_priv *priv) |
188 | { |
189 | struct mlx5e_trap *trap = priv->en_trap; |
190 | |
191 | mlx5e_deactivate_rq(rq: &trap->rq); |
192 | napi_disable(n: &trap->napi); |
193 | } |
194 | |
195 | static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv) |
196 | { |
197 | struct mlx5e_trap *trap; |
198 | |
199 | trap = mlx5e_open_trap(priv); |
200 | if (IS_ERR(ptr: trap)) |
201 | goto out; |
202 | |
203 | mlx5e_activate_trap(trap); |
204 | out: |
205 | return trap; |
206 | } |
207 | |
208 | static void mlx5e_del_trap_queue(struct mlx5e_priv *priv) |
209 | { |
210 | mlx5e_deactivate_trap(priv); |
211 | mlx5e_close_trap(trap: priv->en_trap); |
212 | priv->en_trap = NULL; |
213 | } |
214 | |
215 | static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap) |
216 | { |
217 | return en_trap->tir.tirn; |
218 | } |
219 | |
220 | static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id) |
221 | { |
222 | bool open_queue = !priv->en_trap; |
223 | struct mlx5e_trap *trap; |
224 | int err; |
225 | |
226 | if (open_queue) { |
227 | trap = mlx5e_add_trap_queue(priv); |
228 | if (IS_ERR(ptr: trap)) |
229 | return PTR_ERR(ptr: trap); |
230 | priv->en_trap = trap; |
231 | } |
232 | |
233 | switch (trap_id) { |
234 | case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER: |
235 | err = mlx5e_add_vlan_trap(fs: priv->fs, trap_id, tir_num: mlx5e_trap_get_tirn(en_trap: priv->en_trap)); |
236 | if (err) |
237 | goto err_out; |
238 | break; |
239 | case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER: |
240 | err = mlx5e_add_mac_trap(fs: priv->fs, trap_id, tir_num: mlx5e_trap_get_tirn(en_trap: priv->en_trap)); |
241 | if (err) |
242 | goto err_out; |
243 | break; |
244 | default: |
245 | netdev_warn(dev: priv->netdev, format: "%s: Unknown trap id %d\n" , __func__, trap_id); |
246 | err = -EINVAL; |
247 | goto err_out; |
248 | } |
249 | return 0; |
250 | |
251 | err_out: |
252 | if (open_queue) |
253 | mlx5e_del_trap_queue(priv); |
254 | return err; |
255 | } |
256 | |
257 | static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id) |
258 | { |
259 | switch (trap_id) { |
260 | case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER: |
261 | mlx5e_remove_vlan_trap(fs: priv->fs); |
262 | break; |
263 | case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER: |
264 | mlx5e_remove_mac_trap(fs: priv->fs); |
265 | break; |
266 | default: |
267 | netdev_warn(dev: priv->netdev, format: "%s: Unknown trap id %d\n" , __func__, trap_id); |
268 | return -EINVAL; |
269 | } |
270 | if (priv->en_trap && !mlx5_devlink_trap_get_num_active(dev: priv->mdev)) |
271 | mlx5e_del_trap_queue(priv); |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx) |
277 | { |
278 | int err = 0; |
279 | |
280 | /* Traps are unarmed when interface is down, no need to update |
281 | * them. The configuration is saved in the core driver, |
282 | * queried and applied upon interface up operation in |
283 | * mlx5e_open_locked(). |
284 | */ |
285 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) |
286 | return 0; |
287 | |
288 | switch (trap_ctx->action) { |
289 | case DEVLINK_TRAP_ACTION_TRAP: |
290 | err = mlx5e_handle_action_trap(priv, trap_id: trap_ctx->id); |
291 | break; |
292 | case DEVLINK_TRAP_ACTION_DROP: |
293 | err = mlx5e_handle_action_drop(priv, trap_id: trap_ctx->id); |
294 | break; |
295 | default: |
296 | netdev_warn(dev: priv->netdev, format: "%s: Unsupported action %d\n" , __func__, |
297 | trap_ctx->action); |
298 | err = -EINVAL; |
299 | } |
300 | return err; |
301 | } |
302 | |
303 | static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable) |
304 | { |
305 | enum devlink_trap_action action; |
306 | int err; |
307 | |
308 | err = mlx5_devlink_traps_get_action(dev: priv->mdev, trap_id, action: &action); |
309 | if (err) |
310 | return err; |
311 | if (action == DEVLINK_TRAP_ACTION_TRAP) |
312 | err = enable ? mlx5e_handle_action_trap(priv, trap_id) : |
313 | mlx5e_handle_action_drop(priv, trap_id); |
314 | return err; |
315 | } |
316 | |
317 | static const int mlx5e_traps_arr[] = { |
318 | DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER, |
319 | DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER, |
320 | }; |
321 | |
322 | int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable) |
323 | { |
324 | int err; |
325 | int i; |
326 | |
327 | for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) { |
328 | err = mlx5e_apply_trap(priv, trap_id: mlx5e_traps_arr[i], enable); |
329 | if (err) |
330 | return err; |
331 | } |
332 | return 0; |
333 | } |
334 | |