Merge tag 'soc-drivers-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-block.git] / drivers / net / ethernet / mellanox / mlx5 / core / lib / aso.c
CommitLineData
cdd04f4d
JL
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
4#include <linux/mlx5/device.h>
5#include <linux/mlx5/transobj.h>
0f3caaa2 6#include "clock.h"
cdd04f4d
JL
7#include "aso.h"
8#include "wq.h"
9
10struct mlx5_aso_cq {
11 /* data path - accessed per cqe */
12 struct mlx5_cqwq wq;
13
14 /* data path - accessed per napi poll */
15 struct mlx5_core_cq mcq;
16
17 /* control */
18 struct mlx5_core_dev *mdev;
19 struct mlx5_wq_ctrl wq_ctrl;
20} ____cacheline_aligned_in_smp;
21
22struct mlx5_aso {
23 /* data path */
24 u16 cc;
25 u16 pc;
26
27 struct mlx5_wqe_ctrl_seg *doorbell_cseg;
28 struct mlx5_aso_cq cq;
29
30 /* read only */
31 struct mlx5_wq_cyc wq;
32 void __iomem *uar_map;
33 u32 sqn;
34
35 /* control path */
36 struct mlx5_wq_ctrl wq_ctrl;
37
38} ____cacheline_aligned_in_smp;
39
40static void mlx5_aso_free_cq(struct mlx5_aso_cq *cq)
41{
42 mlx5_wq_destroy(&cq->wq_ctrl);
43}
44
45static int mlx5_aso_alloc_cq(struct mlx5_core_dev *mdev, int numa_node,
46 void *cqc_data, struct mlx5_aso_cq *cq)
47{
48 struct mlx5_core_cq *mcq = &cq->mcq;
49 struct mlx5_wq_param param;
50 int err;
51 u32 i;
52
53 param.buf_numa_node = numa_node;
54 param.db_numa_node = numa_node;
55
56 err = mlx5_cqwq_create(mdev, &param, cqc_data, &cq->wq, &cq->wq_ctrl);
57 if (err)
58 return err;
59
60 mcq->cqe_sz = 64;
61 mcq->set_ci_db = cq->wq_ctrl.db.db;
62 mcq->arm_db = cq->wq_ctrl.db.db + 1;
63
64 for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) {
65 struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(&cq->wq, i);
66
67 cqe->op_own = 0xf1;
68 }
69
70 cq->mdev = mdev;
71
72 return 0;
73}
74
75static int create_aso_cq(struct mlx5_aso_cq *cq, void *cqc_data)
76{
77 u32 out[MLX5_ST_SZ_DW(create_cq_out)];
78 struct mlx5_core_dev *mdev = cq->mdev;
79 struct mlx5_core_cq *mcq = &cq->mcq;
80 void *in, *cqc;
81 int inlen, eqn;
82 int err;
83
f14c1a14 84 err = mlx5_comp_eqn_get(mdev, 0, &eqn);
cdd04f4d
JL
85 if (err)
86 return err;
87
88 inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
89 sizeof(u64) * cq->wq_ctrl.buf.npages;
90 in = kvzalloc(inlen, GFP_KERNEL);
91 if (!in)
92 return -ENOMEM;
93
94 cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context);
95
96 memcpy(cqc, cqc_data, MLX5_ST_SZ_BYTES(cqc));
97
98 mlx5_fill_page_frag_array(&cq->wq_ctrl.buf,
99 (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
100
20cbf8cb 101 MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
cdd04f4d
JL
102 MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
103 MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
104 MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
105 MLX5_ADAPTER_PAGE_SHIFT);
106 MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
107
108 err = mlx5_core_create_cq(mdev, mcq, in, inlen, out, sizeof(out));
109
110 kvfree(in);
111
112 return err;
113}
114
115static void mlx5_aso_destroy_cq(struct mlx5_aso_cq *cq)
116{
117 mlx5_core_destroy_cq(cq->mdev, &cq->mcq);
118 mlx5_wq_destroy(&cq->wq_ctrl);
119}
120
121static int mlx5_aso_create_cq(struct mlx5_core_dev *mdev, int numa_node,
122 struct mlx5_aso_cq *cq)
123{
124 void *cqc_data;
125 int err;
126
127 cqc_data = kvzalloc(MLX5_ST_SZ_BYTES(cqc), GFP_KERNEL);
128 if (!cqc_data)
129 return -ENOMEM;
130
131 MLX5_SET(cqc, cqc_data, log_cq_size, 1);
132 MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index);
133 if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
134 MLX5_SET(cqc, cqc_data, cqe_sz, CQE_STRIDE_128_PAD);
135
136 err = mlx5_aso_alloc_cq(mdev, numa_node, cqc_data, cq);
137 if (err) {
138 mlx5_core_err(mdev, "Failed to alloc aso wq cq, err=%d\n", err);
139 goto err_out;
140 }
141
142 err = create_aso_cq(cq, cqc_data);
143 if (err) {
144 mlx5_core_err(mdev, "Failed to create aso wq cq, err=%d\n", err);
145 goto err_free_cq;
146 }
147
148 kvfree(cqc_data);
149 return 0;
150
151err_free_cq:
152 mlx5_aso_free_cq(cq);
153err_out:
154 kvfree(cqc_data);
155 return err;
156}
157
158static int mlx5_aso_alloc_sq(struct mlx5_core_dev *mdev, int numa_node,
159 void *sqc_data, struct mlx5_aso *sq)
160{
161 void *sqc_wq = MLX5_ADDR_OF(sqc, sqc_data, wq);
162 struct mlx5_wq_cyc *wq = &sq->wq;
163 struct mlx5_wq_param param;
164 int err;
165
166 sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
167
168 param.db_numa_node = numa_node;
169 param.buf_numa_node = numa_node;
170 err = mlx5_wq_cyc_create(mdev, &param, sqc_wq, wq, &sq->wq_ctrl);
171 if (err)
172 return err;
173 wq->db = &wq->db[MLX5_SND_DBR];
174
175 return 0;
176}
177
178static int create_aso_sq(struct mlx5_core_dev *mdev, int pdn,
179 void *sqc_data, struct mlx5_aso *sq)
180{
181 void *in, *sqc, *wq;
182 int inlen, err;
0f3caaa2 183 u8 ts_format;
cdd04f4d
JL
184
185 inlen = MLX5_ST_SZ_BYTES(create_sq_in) +
186 sizeof(u64) * sq->wq_ctrl.buf.npages;
187 in = kvzalloc(inlen, GFP_KERNEL);
188 if (!in)
189 return -ENOMEM;
190
191 sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
192 wq = MLX5_ADDR_OF(sqc, sqc, wq);
193
194 memcpy(sqc, sqc_data, MLX5_ST_SZ_BYTES(sqc));
195 MLX5_SET(sqc, sqc, cqn, sq->cq.mcq.cqn);
196
197 MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST);
198 MLX5_SET(sqc, sqc, flush_in_error_en, 1);
199
0f3caaa2
SM
200 ts_format = mlx5_is_real_time_sq(mdev) ?
201 MLX5_TIMESTAMP_FORMAT_REAL_TIME :
202 MLX5_TIMESTAMP_FORMAT_FREE_RUNNING;
203 MLX5_SET(sqc, sqc, ts_format, ts_format);
204
cdd04f4d
JL
205 MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
206 MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index);
207 MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift -
208 MLX5_ADAPTER_PAGE_SHIFT);
209 MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma);
210
211 mlx5_fill_page_frag_array(&sq->wq_ctrl.buf,
212 (__be64 *)MLX5_ADDR_OF(wq, wq, pas));
213
214 err = mlx5_core_create_sq(mdev, in, inlen, &sq->sqn);
215
216 kvfree(in);
217
218 return err;
219}
220
221static int mlx5_aso_set_sq_rdy(struct mlx5_core_dev *mdev, u32 sqn)
222{
223 void *in, *sqc;
224 int inlen, err;
225
226 inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
227 in = kvzalloc(inlen, GFP_KERNEL);
228 if (!in)
229 return -ENOMEM;
230
231 MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RST);
232 sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
233 MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY);
234
235 err = mlx5_core_modify_sq(mdev, sqn, in);
236
237 kvfree(in);
238
239 return err;
240}
241
242static int mlx5_aso_create_sq_rdy(struct mlx5_core_dev *mdev, u32 pdn,
243 void *sqc_data, struct mlx5_aso *sq)
244{
245 int err;
246
247 err = create_aso_sq(mdev, pdn, sqc_data, sq);
248 if (err)
249 return err;
250
251 err = mlx5_aso_set_sq_rdy(mdev, sq->sqn);
252 if (err)
253 mlx5_core_destroy_sq(mdev, sq->sqn);
254
255 return err;
256}
257
258static void mlx5_aso_free_sq(struct mlx5_aso *sq)
259{
260 mlx5_wq_destroy(&sq->wq_ctrl);
261}
262
263static void mlx5_aso_destroy_sq(struct mlx5_aso *sq)
264{
265 mlx5_core_destroy_sq(sq->cq.mdev, sq->sqn);
266 mlx5_aso_free_sq(sq);
267}
268
269static int mlx5_aso_create_sq(struct mlx5_core_dev *mdev, int numa_node,
270 u32 pdn, struct mlx5_aso *sq)
271{
272 void *sqc_data, *wq;
273 int err;
274
275 sqc_data = kvzalloc(MLX5_ST_SZ_BYTES(sqc), GFP_KERNEL);
276 if (!sqc_data)
277 return -ENOMEM;
278
279 wq = MLX5_ADDR_OF(sqc, sqc_data, wq);
280 MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
281 MLX5_SET(wq, wq, pd, pdn);
282 MLX5_SET(wq, wq, log_wq_sz, 1);
283
284 err = mlx5_aso_alloc_sq(mdev, numa_node, sqc_data, sq);
285 if (err) {
286 mlx5_core_err(mdev, "Failed to alloc aso wq sq, err=%d\n", err);
287 goto err_out;
288 }
289
290 err = mlx5_aso_create_sq_rdy(mdev, pdn, sqc_data, sq);
291 if (err) {
292 mlx5_core_err(mdev, "Failed to open aso wq sq, err=%d\n", err);
293 goto err_free_asosq;
294 }
295
296 mlx5_core_dbg(mdev, "aso sq->sqn = 0x%x\n", sq->sqn);
297
298 kvfree(sqc_data);
299 return 0;
300
301err_free_asosq:
302 mlx5_aso_free_sq(sq);
303err_out:
304 kvfree(sqc_data);
305 return err;
306}
307
308struct mlx5_aso *mlx5_aso_create(struct mlx5_core_dev *mdev, u32 pdn)
309{
310 int numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
311 struct mlx5_aso *aso;
312 int err;
313
314 aso = kzalloc(sizeof(*aso), GFP_KERNEL);
315 if (!aso)
316 return ERR_PTR(-ENOMEM);
317
318 err = mlx5_aso_create_cq(mdev, numa_node, &aso->cq);
319 if (err)
320 goto err_cq;
321
322 err = mlx5_aso_create_sq(mdev, numa_node, pdn, aso);
323 if (err)
324 goto err_sq;
325
326 return aso;
327
328err_sq:
329 mlx5_aso_destroy_cq(&aso->cq);
330err_cq:
331 kfree(aso);
332 return ERR_PTR(err);
333}
334
335void mlx5_aso_destroy(struct mlx5_aso *aso)
336{
cdd04f4d
JL
337 mlx5_aso_destroy_sq(aso);
338 mlx5_aso_destroy_cq(&aso->cq);
339 kfree(aso);
340}
c491ded0
JL
341
342void mlx5_aso_build_wqe(struct mlx5_aso *aso, u8 ds_cnt,
343 struct mlx5_aso_wqe *aso_wqe,
344 u32 obj_id, u32 opc_mode)
345{
346 struct mlx5_wqe_ctrl_seg *cseg = &aso_wqe->ctrl;
347
348 cseg->opmod_idx_opcode = cpu_to_be32((opc_mode << MLX5_WQE_CTRL_WQE_OPC_MOD_SHIFT) |
349 (aso->pc << MLX5_WQE_CTRL_WQE_INDEX_SHIFT) |
350 MLX5_OPCODE_ACCESS_ASO);
351 cseg->qpn_ds = cpu_to_be32((aso->sqn << MLX5_WQE_CTRL_QPN_SHIFT) | ds_cnt);
352 cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
353 cseg->general_id = cpu_to_be32(obj_id);
354}
355
e77bbde7 356struct mlx5_aso_wqe *mlx5_aso_get_wqe(struct mlx5_aso *aso)
c491ded0 357{
e77bbde7 358 struct mlx5_aso_wqe *wqe;
c491ded0
JL
359 u16 pi;
360
361 pi = mlx5_wq_cyc_ctr2ix(&aso->wq, aso->pc);
e77bbde7
LR
362 wqe = mlx5_wq_cyc_get_wqe(&aso->wq, pi);
363 memset(wqe, 0, sizeof(*wqe));
364 return wqe;
c491ded0
JL
365}
366
367void mlx5_aso_post_wqe(struct mlx5_aso *aso, bool with_data,
368 struct mlx5_wqe_ctrl_seg *doorbell_cseg)
369{
370 doorbell_cseg->fm_ce_se |= MLX5_WQE_CTRL_CQ_UPDATE;
371 /* ensure wqe is visible to device before updating doorbell record */
372 dma_wmb();
373
374 if (with_data)
375 aso->pc += MLX5_ASO_WQEBBS_DATA;
376 else
377 aso->pc += MLX5_ASO_WQEBBS;
378 *aso->wq.db = cpu_to_be32(aso->pc);
379
380 /* ensure doorbell record is visible to device before ringing the
381 * doorbell
382 */
383 wmb();
384
385 mlx5_write64((__be32 *)doorbell_cseg, aso->uar_map);
386
387 /* Ensure doorbell is written on uar_page before poll_cq */
388 WRITE_ONCE(doorbell_cseg, NULL);
389}
390
739cfa34 391int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data)
c491ded0
JL
392{
393 struct mlx5_aso_cq *cq = &aso->cq;
394 struct mlx5_cqe64 *cqe;
c491ded0
JL
395
396 cqe = mlx5_cqwq_get_cqe(&cq->wq);
c491ded0
JL
397 if (!cqe)
398 return -ETIMEDOUT;
399
400 /* sq->cc must be updated only after mlx5_cqwq_update_db_record(),
401 * otherwise a cq overrun may occur
402 */
403 mlx5_cqwq_pop(&cq->wq);
404
405 if (unlikely(get_cqe_opcode(cqe) != MLX5_CQE_REQ)) {
406 struct mlx5_err_cqe *err_cqe;
407
408 mlx5_core_err(cq->mdev, "Bad OP in ASOSQ CQE: 0x%x\n",
409 get_cqe_opcode(cqe));
410
411 err_cqe = (struct mlx5_err_cqe *)cqe;
412 mlx5_core_err(cq->mdev, "vendor_err_synd=%x\n",
413 err_cqe->vendor_err_synd);
414 mlx5_core_err(cq->mdev, "syndrome=%x\n",
415 err_cqe->syndrome);
416 print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET,
417 16, 1, err_cqe,
418 sizeof(*err_cqe), false);
419 }
420
421 mlx5_cqwq_update_db_record(&cq->wq);
422
423 /* ensure cq space is freed before enabling more cqes */
424 wmb();
425
426 if (with_data)
427 aso->cc += MLX5_ASO_WQEBBS_DATA;
428 else
429 aso->cc += MLX5_ASO_WQEBBS;
430
431 return 0;
432}