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