1 /*
2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33 #include <linux/interrupt.h>
34 #include <linux/notifier.h>
35 #include <linux/module.h>
36 #include <linux/mlx5/driver.h>
37 #include <linux/mlx5/vport.h>
38 #include <linux/mlx5/eq.h>
39 #ifdef CONFIG_RFS_ACCEL
40 #include <linux/cpu_rmap.h>
41 #endif
42 #include "mlx5_core.h"
43 #include "lib/eq.h"
44 #include "fpga/core.h"
45 #include "eswitch.h"
46 #include "lib/clock.h"
47 #include "diag/fw_tracer.h"
48
49 enum {
50 MLX5_EQE_OWNER_INIT_VAL = 0x1,
51 };
52
53 enum {
54 MLX5_EQ_STATE_ARMED = 0x9,
55 MLX5_EQ_STATE_FIRED = 0xa,
56 MLX5_EQ_STATE_ALWAYS_ARMED = 0xb,
57 };
58
59 enum {
60 MLX5_EQ_DOORBEL_OFFSET = 0x40,
61 };
62
63 /* budget must be smaller than MLX5_NUM_SPARE_EQE to guarantee that we update
64 * the ci before we polled all the entries in the EQ. MLX5_NUM_SPARE_EQE is
65 * used to set the EQ size, budget must be smaller than the EQ size.
66 */
67 enum {
68 MLX5_EQ_POLLING_BUDGET = 128,
69 };
70
71 static_assert(MLX5_EQ_POLLING_BUDGET <= MLX5_NUM_SPARE_EQE);
72
73 struct mlx5_eq_table {
74 struct list_head comp_eqs_list;
75 struct mlx5_eq_async pages_eq;
76 struct mlx5_eq_async cmd_eq;
77 struct mlx5_eq_async async_eq;
78
79 struct atomic_notifier_head nh[MLX5_EVENT_TYPE_MAX];
80
81 /* Since CQ DB is stored in async_eq */
82 struct mlx5_nb cq_err_nb;
83
84 struct mutex lock; /* sync async eqs creations */
85 int num_comp_eqs;
86 struct mlx5_irq_table *irq_table;
87 };
88
89 #define MLX5_ASYNC_EVENT_MASK ((1ull << MLX5_EVENT_TYPE_PATH_MIG) | \
90 (1ull << MLX5_EVENT_TYPE_COMM_EST) | \
91 (1ull << MLX5_EVENT_TYPE_SQ_DRAINED) | \
92 (1ull << MLX5_EVENT_TYPE_CQ_ERROR) | \
93 (1ull << MLX5_EVENT_TYPE_WQ_CATAS_ERROR) | \
94 (1ull << MLX5_EVENT_TYPE_PATH_MIG_FAILED) | \
95 (1ull << MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
96 (1ull << MLX5_EVENT_TYPE_WQ_ACCESS_ERROR) | \
97 (1ull << MLX5_EVENT_TYPE_PORT_CHANGE) | \
98 (1ull << MLX5_EVENT_TYPE_SRQ_CATAS_ERROR) | \
99 (1ull << MLX5_EVENT_TYPE_SRQ_LAST_WQE) | \
100 (1ull << MLX5_EVENT_TYPE_SRQ_RQ_LIMIT))
101
mlx5_cmd_destroy_eq(struct mlx5_core_dev * dev,u8 eqn)102 static int mlx5_cmd_destroy_eq(struct mlx5_core_dev *dev, u8 eqn)
103 {
104 u32 in[MLX5_ST_SZ_DW(destroy_eq_in)] = {};
105
106 MLX5_SET(destroy_eq_in, in, opcode, MLX5_CMD_OP_DESTROY_EQ);
107 MLX5_SET(destroy_eq_in, in, eq_number, eqn);
108 return mlx5_cmd_exec_in(dev, destroy_eq, in);
109 }
110
111 /* caller must eventually call mlx5_cq_put on the returned cq */
mlx5_eq_cq_get(struct mlx5_eq * eq,u32 cqn)112 static struct mlx5_core_cq *mlx5_eq_cq_get(struct mlx5_eq *eq, u32 cqn)
113 {
114 struct mlx5_cq_table *table = &eq->cq_table;
115 struct mlx5_core_cq *cq = NULL;
116
117 rcu_read_lock();
118 cq = radix_tree_lookup(&table->tree, cqn);
119 if (likely(cq))
120 mlx5_cq_hold(cq);
121 rcu_read_unlock();
122
123 return cq;
124 }
125
mlx5_eq_comp_int(struct notifier_block * nb,__always_unused unsigned long action,__always_unused void * data)126 static int mlx5_eq_comp_int(struct notifier_block *nb,
127 __always_unused unsigned long action,
128 __always_unused void *data)
129 {
130 struct mlx5_eq_comp *eq_comp =
131 container_of(nb, struct mlx5_eq_comp, irq_nb);
132 struct mlx5_eq *eq = &eq_comp->core;
133 struct mlx5_eqe *eqe;
134 int num_eqes = 0;
135 u32 cqn = -1;
136
137 eqe = next_eqe_sw(eq);
138 if (!eqe)
139 goto out;
140
141 do {
142 struct mlx5_core_cq *cq;
143
144 /* Make sure we read EQ entry contents after we've
145 * checked the ownership bit.
146 */
147 dma_rmb();
148 /* Assume (eqe->type) is always MLX5_EVENT_TYPE_COMP */
149 cqn = be32_to_cpu(eqe->data.comp.cqn) & 0xffffff;
150
151 cq = mlx5_eq_cq_get(eq, cqn);
152 if (likely(cq)) {
153 ++cq->arm_sn;
154 cq->comp(cq, eqe);
155 mlx5_cq_put(cq);
156 } else {
157 dev_dbg_ratelimited(eq->dev->device,
158 "Completion event for bogus CQ 0x%x\n", cqn);
159 }
160
161 ++eq->cons_index;
162
163 } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
164
165 out:
166 eq_update_ci(eq, 1);
167
168 if (cqn != -1)
169 tasklet_schedule(&eq_comp->tasklet_ctx.task);
170
171 return 0;
172 }
173
174 /* Some architectures don't latch interrupts when they are disabled, so using
175 * mlx5_eq_poll_irq_disabled could end up losing interrupts while trying to
176 * avoid losing them. It is not recommended to use it, unless this is the last
177 * resort.
178 */
mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp * eq)179 u32 mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp *eq)
180 {
181 u32 count_eqe;
182
183 disable_irq(eq->core.irqn);
184 count_eqe = eq->core.cons_index;
185 mlx5_eq_comp_int(&eq->irq_nb, 0, NULL);
186 count_eqe = eq->core.cons_index - count_eqe;
187 enable_irq(eq->core.irqn);
188
189 return count_eqe;
190 }
191
mlx5_eq_async_int_lock(struct mlx5_eq_async * eq,unsigned long * flags)192 static void mlx5_eq_async_int_lock(struct mlx5_eq_async *eq, unsigned long *flags)
193 __acquires(&eq->lock)
194 {
195 if (in_irq())
196 spin_lock(&eq->lock);
197 else
198 spin_lock_irqsave(&eq->lock, *flags);
199 }
200
mlx5_eq_async_int_unlock(struct mlx5_eq_async * eq,unsigned long * flags)201 static void mlx5_eq_async_int_unlock(struct mlx5_eq_async *eq, unsigned long *flags)
202 __releases(&eq->lock)
203 {
204 if (in_irq())
205 spin_unlock(&eq->lock);
206 else
207 spin_unlock_irqrestore(&eq->lock, *flags);
208 }
209
210 enum async_eq_nb_action {
211 ASYNC_EQ_IRQ_HANDLER = 0,
212 ASYNC_EQ_RECOVER = 1,
213 };
214
mlx5_eq_async_int(struct notifier_block * nb,unsigned long action,void * data)215 static int mlx5_eq_async_int(struct notifier_block *nb,
216 unsigned long action, void *data)
217 {
218 struct mlx5_eq_async *eq_async =
219 container_of(nb, struct mlx5_eq_async, irq_nb);
220 struct mlx5_eq *eq = &eq_async->core;
221 struct mlx5_eq_table *eqt;
222 struct mlx5_core_dev *dev;
223 struct mlx5_eqe *eqe;
224 unsigned long flags;
225 int num_eqes = 0;
226
227 dev = eq->dev;
228 eqt = dev->priv.eq_table;
229
230 mlx5_eq_async_int_lock(eq_async, &flags);
231
232 eqe = next_eqe_sw(eq);
233 if (!eqe)
234 goto out;
235
236 do {
237 /*
238 * Make sure we read EQ entry contents after we've
239 * checked the ownership bit.
240 */
241 dma_rmb();
242
243 atomic_notifier_call_chain(&eqt->nh[eqe->type], eqe->type, eqe);
244 atomic_notifier_call_chain(&eqt->nh[MLX5_EVENT_TYPE_NOTIFY_ANY], eqe->type, eqe);
245
246 ++eq->cons_index;
247
248 } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
249
250 out:
251 eq_update_ci(eq, 1);
252 mlx5_eq_async_int_unlock(eq_async, &flags);
253
254 return unlikely(action == ASYNC_EQ_RECOVER) ? num_eqes : 0;
255 }
256
mlx5_cmd_eq_recover(struct mlx5_core_dev * dev)257 void mlx5_cmd_eq_recover(struct mlx5_core_dev *dev)
258 {
259 struct mlx5_eq_async *eq = &dev->priv.eq_table->cmd_eq;
260 int eqes;
261
262 eqes = mlx5_eq_async_int(&eq->irq_nb, ASYNC_EQ_RECOVER, NULL);
263 if (eqes)
264 mlx5_core_warn(dev, "Recovered %d EQEs on cmd_eq\n", eqes);
265 }
266
init_eq_buf(struct mlx5_eq * eq)267 static void init_eq_buf(struct mlx5_eq *eq)
268 {
269 struct mlx5_eqe *eqe;
270 int i;
271
272 for (i = 0; i < eq->nent; i++) {
273 eqe = get_eqe(eq, i);
274 eqe->owner = MLX5_EQE_OWNER_INIT_VAL;
275 }
276 }
277
278 static int
create_map_eq(struct mlx5_core_dev * dev,struct mlx5_eq * eq,struct mlx5_eq_param * param)279 create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
280 struct mlx5_eq_param *param)
281 {
282 struct mlx5_cq_table *cq_table = &eq->cq_table;
283 u32 out[MLX5_ST_SZ_DW(create_eq_out)] = {0};
284 struct mlx5_priv *priv = &dev->priv;
285 u8 vecidx = param->irq_index;
286 __be64 *pas;
287 void *eqc;
288 int inlen;
289 u32 *in;
290 int err;
291 int i;
292
293 /* Init CQ table */
294 memset(cq_table, 0, sizeof(*cq_table));
295 spin_lock_init(&cq_table->lock);
296 INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC);
297
298 eq->nent = roundup_pow_of_two(param->nent + MLX5_NUM_SPARE_EQE);
299 eq->cons_index = 0;
300 err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, &eq->buf);
301 if (err)
302 return err;
303
304 init_eq_buf(eq);
305
306 inlen = MLX5_ST_SZ_BYTES(create_eq_in) +
307 MLX5_FLD_SZ_BYTES(create_eq_in, pas[0]) * eq->buf.npages;
308
309 in = kvzalloc(inlen, GFP_KERNEL);
310 if (!in) {
311 err = -ENOMEM;
312 goto err_buf;
313 }
314
315 pas = (__be64 *)MLX5_ADDR_OF(create_eq_in, in, pas);
316 mlx5_fill_page_array(&eq->buf, pas);
317
318 MLX5_SET(create_eq_in, in, opcode, MLX5_CMD_OP_CREATE_EQ);
319 if (!param->mask[0] && MLX5_CAP_GEN(dev, log_max_uctx))
320 MLX5_SET(create_eq_in, in, uid, MLX5_SHARED_RESOURCE_UID);
321
322 for (i = 0; i < 4; i++)
323 MLX5_ARRAY_SET64(create_eq_in, in, event_bitmask, i,
324 param->mask[i]);
325
326 eqc = MLX5_ADDR_OF(create_eq_in, in, eq_context_entry);
327 MLX5_SET(eqc, eqc, log_eq_size, ilog2(eq->nent));
328 MLX5_SET(eqc, eqc, uar_page, priv->uar->index);
329 MLX5_SET(eqc, eqc, intr, vecidx);
330 MLX5_SET(eqc, eqc, log_page_size,
331 eq->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
332
333 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
334 if (err)
335 goto err_in;
336
337 eq->vecidx = vecidx;
338 eq->eqn = MLX5_GET(create_eq_out, out, eq_number);
339 eq->irqn = pci_irq_vector(dev->pdev, vecidx);
340 eq->dev = dev;
341 eq->doorbell = priv->uar->map + MLX5_EQ_DOORBEL_OFFSET;
342
343 err = mlx5_debug_eq_add(dev, eq);
344 if (err)
345 goto err_eq;
346
347 kvfree(in);
348 return 0;
349
350 err_eq:
351 mlx5_cmd_destroy_eq(dev, eq->eqn);
352
353 err_in:
354 kvfree(in);
355
356 err_buf:
357 mlx5_buf_free(dev, &eq->buf);
358 return err;
359 }
360
361 /**
362 * mlx5_eq_enable - Enable EQ for receiving EQEs
363 * @dev : Device which owns the eq
364 * @eq : EQ to enable
365 * @nb : Notifier call block
366 *
367 * Must be called after EQ is created in device.
368 *
369 * @return: 0 if no error
370 */
mlx5_eq_enable(struct mlx5_core_dev * dev,struct mlx5_eq * eq,struct notifier_block * nb)371 int mlx5_eq_enable(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
372 struct notifier_block *nb)
373 {
374 struct mlx5_eq_table *eq_table = dev->priv.eq_table;
375 int err;
376
377 err = mlx5_irq_attach_nb(eq_table->irq_table, eq->vecidx, nb);
378 if (!err)
379 eq_update_ci(eq, 1);
380
381 return err;
382 }
383 EXPORT_SYMBOL(mlx5_eq_enable);
384
385 /**
386 * mlx5_eq_disable - Disable EQ for receiving EQEs
387 * @dev : Device which owns the eq
388 * @eq : EQ to disable
389 * @nb : Notifier call block
390 *
391 * Must be called before EQ is destroyed.
392 */
mlx5_eq_disable(struct mlx5_core_dev * dev,struct mlx5_eq * eq,struct notifier_block * nb)393 void mlx5_eq_disable(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
394 struct notifier_block *nb)
395 {
396 struct mlx5_eq_table *eq_table = dev->priv.eq_table;
397
398 mlx5_irq_detach_nb(eq_table->irq_table, eq->vecidx, nb);
399 }
400 EXPORT_SYMBOL(mlx5_eq_disable);
401
destroy_unmap_eq(struct mlx5_core_dev * dev,struct mlx5_eq * eq)402 static int destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
403 {
404 int err;
405
406 mlx5_debug_eq_remove(dev, eq);
407
408 err = mlx5_cmd_destroy_eq(dev, eq->eqn);
409 if (err)
410 mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n",
411 eq->eqn);
412 synchronize_irq(eq->irqn);
413
414 mlx5_buf_free(dev, &eq->buf);
415
416 return err;
417 }
418
mlx5_eq_add_cq(struct mlx5_eq * eq,struct mlx5_core_cq * cq)419 int mlx5_eq_add_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq)
420 {
421 struct mlx5_cq_table *table = &eq->cq_table;
422 int err;
423
424 spin_lock(&table->lock);
425 err = radix_tree_insert(&table->tree, cq->cqn, cq);
426 spin_unlock(&table->lock);
427
428 return err;
429 }
430
mlx5_eq_del_cq(struct mlx5_eq * eq,struct mlx5_core_cq * cq)431 void mlx5_eq_del_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq)
432 {
433 struct mlx5_cq_table *table = &eq->cq_table;
434 struct mlx5_core_cq *tmp;
435
436 spin_lock(&table->lock);
437 tmp = radix_tree_delete(&table->tree, cq->cqn);
438 spin_unlock(&table->lock);
439
440 if (!tmp) {
441 mlx5_core_dbg(eq->dev, "cq 0x%x not found in eq 0x%x tree\n",
442 eq->eqn, cq->cqn);
443 return;
444 }
445
446 if (tmp != cq)
447 mlx5_core_dbg(eq->dev, "corruption on cqn 0x%x in eq 0x%x\n",
448 eq->eqn, cq->cqn);
449 }
450
mlx5_eq_table_init(struct mlx5_core_dev * dev)451 int mlx5_eq_table_init(struct mlx5_core_dev *dev)
452 {
453 struct mlx5_eq_table *eq_table;
454 int i;
455
456 eq_table = kvzalloc(sizeof(*eq_table), GFP_KERNEL);
457 if (!eq_table)
458 return -ENOMEM;
459
460 dev->priv.eq_table = eq_table;
461
462 mlx5_eq_debugfs_init(dev);
463
464 mutex_init(&eq_table->lock);
465 for (i = 0; i < MLX5_EVENT_TYPE_MAX; i++)
466 ATOMIC_INIT_NOTIFIER_HEAD(&eq_table->nh[i]);
467
468 eq_table->irq_table = dev->priv.irq_table;
469 return 0;
470 }
471
mlx5_eq_table_cleanup(struct mlx5_core_dev * dev)472 void mlx5_eq_table_cleanup(struct mlx5_core_dev *dev)
473 {
474 mlx5_eq_debugfs_cleanup(dev);
475 kvfree(dev->priv.eq_table);
476 }
477
478 /* Async EQs */
479
create_async_eq(struct mlx5_core_dev * dev,struct mlx5_eq * eq,struct mlx5_eq_param * param)480 static int create_async_eq(struct mlx5_core_dev *dev,
481 struct mlx5_eq *eq, struct mlx5_eq_param *param)
482 {
483 struct mlx5_eq_table *eq_table = dev->priv.eq_table;
484 int err;
485
486 mutex_lock(&eq_table->lock);
487 /* Async EQs must share irq index 0 */
488 if (param->irq_index != 0) {
489 err = -EINVAL;
490 goto unlock;
491 }
492
493 err = create_map_eq(dev, eq, param);
494 unlock:
495 mutex_unlock(&eq_table->lock);
496 return err;
497 }
498
destroy_async_eq(struct mlx5_core_dev * dev,struct mlx5_eq * eq)499 static int destroy_async_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
500 {
501 struct mlx5_eq_table *eq_table = dev->priv.eq_table;
502 int err;
503
504 mutex_lock(&eq_table->lock);
505 err = destroy_unmap_eq(dev, eq);
506 mutex_unlock(&eq_table->lock);
507 return err;
508 }
509
cq_err_event_notifier(struct notifier_block * nb,unsigned long type,void * data)510 static int cq_err_event_notifier(struct notifier_block *nb,
511 unsigned long type, void *data)
512 {
513 struct mlx5_eq_table *eqt;
514 struct mlx5_core_cq *cq;
515 struct mlx5_eqe *eqe;
516 struct mlx5_eq *eq;
517 u32 cqn;
518
519 /* type == MLX5_EVENT_TYPE_CQ_ERROR */
520
521 eqt = mlx5_nb_cof(nb, struct mlx5_eq_table, cq_err_nb);
522 eq = &eqt->async_eq.core;
523 eqe = data;
524
525 cqn = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff;
526 mlx5_core_warn(eq->dev, "CQ error on CQN 0x%x, syndrome 0x%x\n",
527 cqn, eqe->data.cq_err.syndrome);
528
529 cq = mlx5_eq_cq_get(eq, cqn);
530 if (unlikely(!cq)) {
531 mlx5_core_warn(eq->dev, "Async event for bogus CQ 0x%x\n", cqn);
532 return NOTIFY_OK;
533 }
534
535 if (cq->event)
536 cq->event(cq, type);
537
538 mlx5_cq_put(cq);
539
540 return NOTIFY_OK;
541 }
542
gather_user_async_events(struct mlx5_core_dev * dev,u64 mask[4])543 static void gather_user_async_events(struct mlx5_core_dev *dev, u64 mask[4])
544 {
545 __be64 *user_unaffiliated_events;
546 __be64 *user_affiliated_events;
547 int i;
548
549 user_affiliated_events =
550 MLX5_CAP_DEV_EVENT(dev, user_affiliated_events);
551 user_unaffiliated_events =
552 MLX5_CAP_DEV_EVENT(dev, user_unaffiliated_events);
553
554 for (i = 0; i < 4; i++)
555 mask[i] |= be64_to_cpu(user_affiliated_events[i] |
556 user_unaffiliated_events[i]);
557 }
558
gather_async_events_mask(struct mlx5_core_dev * dev,u64 mask[4])559 static void gather_async_events_mask(struct mlx5_core_dev *dev, u64 mask[4])
560 {
561 u64 async_event_mask = MLX5_ASYNC_EVENT_MASK;
562
563 if (MLX5_VPORT_MANAGER(dev))
564 async_event_mask |= (1ull << MLX5_EVENT_TYPE_NIC_VPORT_CHANGE);
565
566 if (MLX5_CAP_GEN(dev, general_notification_event))
567 async_event_mask |= (1ull << MLX5_EVENT_TYPE_GENERAL_EVENT);
568
569 if (MLX5_CAP_GEN(dev, port_module_event))
570 async_event_mask |= (1ull << MLX5_EVENT_TYPE_PORT_MODULE_EVENT);
571 else
572 mlx5_core_dbg(dev, "port_module_event is not set\n");
573
574 if (MLX5_PPS_CAP(dev))
575 async_event_mask |= (1ull << MLX5_EVENT_TYPE_PPS_EVENT);
576
577 if (MLX5_CAP_GEN(dev, fpga))
578 async_event_mask |= (1ull << MLX5_EVENT_TYPE_FPGA_ERROR) |
579 (1ull << MLX5_EVENT_TYPE_FPGA_QP_ERROR);
580 if (MLX5_CAP_GEN_MAX(dev, dct))
581 async_event_mask |= (1ull << MLX5_EVENT_TYPE_DCT_DRAINED);
582
583 if (MLX5_CAP_GEN(dev, temp_warn_event))
584 async_event_mask |= (1ull << MLX5_EVENT_TYPE_TEMP_WARN_EVENT);
585
586 if (MLX5_CAP_MCAM_REG(dev, tracer_registers))
587 async_event_mask |= (1ull << MLX5_EVENT_TYPE_DEVICE_TRACER);
588
589 if (MLX5_CAP_GEN(dev, max_num_of_monitor_counters))
590 async_event_mask |= (1ull << MLX5_EVENT_TYPE_MONITOR_COUNTER);
591
592 if (mlx5_eswitch_is_funcs_handler(dev))
593 async_event_mask |=
594 (1ull << MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED);
595
596 mask[0] = async_event_mask;
597
598 if (MLX5_CAP_GEN(dev, event_cap))
599 gather_user_async_events(dev, mask);
600 }
601
602 static int
setup_async_eq(struct mlx5_core_dev * dev,struct mlx5_eq_async * eq,struct mlx5_eq_param * param,const char * name)603 setup_async_eq(struct mlx5_core_dev *dev, struct mlx5_eq_async *eq,
604 struct mlx5_eq_param *param, const char *name)
605 {
606 int err;
607
608 eq->irq_nb.notifier_call = mlx5_eq_async_int;
609 spin_lock_init(&eq->lock);
610
611 err = create_async_eq(dev, &eq->core, param);
612 if (err) {
613 mlx5_core_warn(dev, "failed to create %s EQ %d\n", name, err);
614 return err;
615 }
616 err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb);
617 if (err) {
618 mlx5_core_warn(dev, "failed to enable %s EQ %d\n", name, err);
619 destroy_async_eq(dev, &eq->core);
620 }
621 return err;
622 }
623
cleanup_async_eq(struct mlx5_core_dev * dev,struct mlx5_eq_async * eq,const char * name)624 static void cleanup_async_eq(struct mlx5_core_dev *dev,
625 struct mlx5_eq_async *eq, const char *name)
626 {
627 int err;
628
629 mlx5_eq_disable(dev, &eq->core, &eq->irq_nb);
630 err = destroy_async_eq(dev, &eq->core);
631 if (err)
632 mlx5_core_err(dev, "failed to destroy %s eq, err(%d)\n",
633 name, err);
634 }
635
create_async_eqs(struct mlx5_core_dev * dev)636 static int create_async_eqs(struct mlx5_core_dev *dev)
637 {
638 struct mlx5_eq_table *table = dev->priv.eq_table;
639 struct mlx5_eq_param param = {};
640 int err;
641
642 MLX5_NB_INIT(&table->cq_err_nb, cq_err_event_notifier, CQ_ERROR);
643 mlx5_eq_notifier_register(dev, &table->cq_err_nb);
644
645 param = (struct mlx5_eq_param) {
646 .irq_index = 0,
647 .nent = MLX5_NUM_CMD_EQE,
648 .mask[0] = 1ull << MLX5_EVENT_TYPE_CMD,
649 };
650 mlx5_cmd_allowed_opcode(dev, MLX5_CMD_OP_CREATE_EQ);
651 err = setup_async_eq(dev, &table->cmd_eq, ¶m, "cmd");
652 if (err)
653 goto err1;
654
655 mlx5_cmd_use_events(dev);
656 mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
657
658 param = (struct mlx5_eq_param) {
659 .irq_index = 0,
660 .nent = MLX5_NUM_ASYNC_EQE,
661 };
662
663 gather_async_events_mask(dev, param.mask);
664 err = setup_async_eq(dev, &table->async_eq, ¶m, "async");
665 if (err)
666 goto err2;
667
668 param = (struct mlx5_eq_param) {
669 .irq_index = 0,
670 .nent = /* TODO: sriov max_vf + */ 1,
671 .mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_REQUEST,
672 };
673
674 err = setup_async_eq(dev, &table->pages_eq, ¶m, "pages");
675 if (err)
676 goto err3;
677
678 return 0;
679
680 err3:
681 cleanup_async_eq(dev, &table->async_eq, "async");
682 err2:
683 mlx5_cmd_use_polling(dev);
684 cleanup_async_eq(dev, &table->cmd_eq, "cmd");
685 err1:
686 mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
687 mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
688 return err;
689 }
690
destroy_async_eqs(struct mlx5_core_dev * dev)691 static void destroy_async_eqs(struct mlx5_core_dev *dev)
692 {
693 struct mlx5_eq_table *table = dev->priv.eq_table;
694
695 cleanup_async_eq(dev, &table->pages_eq, "pages");
696 cleanup_async_eq(dev, &table->async_eq, "async");
697 mlx5_cmd_allowed_opcode(dev, MLX5_CMD_OP_DESTROY_EQ);
698 mlx5_cmd_use_polling(dev);
699 cleanup_async_eq(dev, &table->cmd_eq, "cmd");
700 mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
701 mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
702 }
703
mlx5_get_async_eq(struct mlx5_core_dev * dev)704 struct mlx5_eq *mlx5_get_async_eq(struct mlx5_core_dev *dev)
705 {
706 return &dev->priv.eq_table->async_eq.core;
707 }
708
mlx5_eq_synchronize_async_irq(struct mlx5_core_dev * dev)709 void mlx5_eq_synchronize_async_irq(struct mlx5_core_dev *dev)
710 {
711 synchronize_irq(dev->priv.eq_table->async_eq.core.irqn);
712 }
713
mlx5_eq_synchronize_cmd_irq(struct mlx5_core_dev * dev)714 void mlx5_eq_synchronize_cmd_irq(struct mlx5_core_dev *dev)
715 {
716 synchronize_irq(dev->priv.eq_table->cmd_eq.core.irqn);
717 }
718
719 /* Generic EQ API for mlx5_core consumers
720 * Needed For RDMA ODP EQ for now
721 */
722 struct mlx5_eq *
mlx5_eq_create_generic(struct mlx5_core_dev * dev,struct mlx5_eq_param * param)723 mlx5_eq_create_generic(struct mlx5_core_dev *dev,
724 struct mlx5_eq_param *param)
725 {
726 struct mlx5_eq *eq = kvzalloc(sizeof(*eq), GFP_KERNEL);
727 int err;
728
729 if (!eq)
730 return ERR_PTR(-ENOMEM);
731
732 err = create_async_eq(dev, eq, param);
733 if (err) {
734 kvfree(eq);
735 eq = ERR_PTR(err);
736 }
737
738 return eq;
739 }
740 EXPORT_SYMBOL(mlx5_eq_create_generic);
741
mlx5_eq_destroy_generic(struct mlx5_core_dev * dev,struct mlx5_eq * eq)742 int mlx5_eq_destroy_generic(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
743 {
744 int err;
745
746 if (IS_ERR(eq))
747 return -EINVAL;
748
749 err = destroy_async_eq(dev, eq);
750 if (err)
751 goto out;
752
753 kvfree(eq);
754 out:
755 return err;
756 }
757 EXPORT_SYMBOL(mlx5_eq_destroy_generic);
758
mlx5_eq_get_eqe(struct mlx5_eq * eq,u32 cc)759 struct mlx5_eqe *mlx5_eq_get_eqe(struct mlx5_eq *eq, u32 cc)
760 {
761 u32 ci = eq->cons_index + cc;
762 struct mlx5_eqe *eqe;
763
764 eqe = get_eqe(eq, ci & (eq->nent - 1));
765 eqe = ((eqe->owner & 1) ^ !!(ci & eq->nent)) ? NULL : eqe;
766 /* Make sure we read EQ entry contents after we've
767 * checked the ownership bit.
768 */
769 if (eqe)
770 dma_rmb();
771
772 return eqe;
773 }
774 EXPORT_SYMBOL(mlx5_eq_get_eqe);
775
mlx5_eq_update_ci(struct mlx5_eq * eq,u32 cc,bool arm)776 void mlx5_eq_update_ci(struct mlx5_eq *eq, u32 cc, bool arm)
777 {
778 __be32 __iomem *addr = eq->doorbell + (arm ? 0 : 2);
779 u32 val;
780
781 eq->cons_index += cc;
782 val = (eq->cons_index & 0xffffff) | (eq->eqn << 24);
783
784 __raw_writel((__force u32)cpu_to_be32(val), addr);
785 /* We still want ordering, just not swabbing, so add a barrier */
786 wmb();
787 }
788 EXPORT_SYMBOL(mlx5_eq_update_ci);
789
destroy_comp_eqs(struct mlx5_core_dev * dev)790 static void destroy_comp_eqs(struct mlx5_core_dev *dev)
791 {
792 struct mlx5_eq_table *table = dev->priv.eq_table;
793 struct mlx5_eq_comp *eq, *n;
794
795 list_for_each_entry_safe(eq, n, &table->comp_eqs_list, list) {
796 list_del(&eq->list);
797 mlx5_eq_disable(dev, &eq->core, &eq->irq_nb);
798 if (destroy_unmap_eq(dev, &eq->core))
799 mlx5_core_warn(dev, "failed to destroy comp EQ 0x%x\n",
800 eq->core.eqn);
801 tasklet_disable(&eq->tasklet_ctx.task);
802 kfree(eq);
803 }
804 }
805
create_comp_eqs(struct mlx5_core_dev * dev)806 static int create_comp_eqs(struct mlx5_core_dev *dev)
807 {
808 struct mlx5_eq_table *table = dev->priv.eq_table;
809 struct mlx5_eq_comp *eq;
810 int ncomp_eqs;
811 int nent;
812 int err;
813 int i;
814
815 INIT_LIST_HEAD(&table->comp_eqs_list);
816 ncomp_eqs = table->num_comp_eqs;
817 nent = MLX5_COMP_EQ_SIZE;
818 for (i = 0; i < ncomp_eqs; i++) {
819 int vecidx = i + MLX5_IRQ_VEC_COMP_BASE;
820 struct mlx5_eq_param param = {};
821
822 eq = kzalloc(sizeof(*eq), GFP_KERNEL);
823 if (!eq) {
824 err = -ENOMEM;
825 goto clean;
826 }
827
828 INIT_LIST_HEAD(&eq->tasklet_ctx.list);
829 INIT_LIST_HEAD(&eq->tasklet_ctx.process_list);
830 spin_lock_init(&eq->tasklet_ctx.lock);
831 tasklet_setup(&eq->tasklet_ctx.task, mlx5_cq_tasklet_cb);
832
833 eq->irq_nb.notifier_call = mlx5_eq_comp_int;
834 param = (struct mlx5_eq_param) {
835 .irq_index = vecidx,
836 .nent = nent,
837 };
838 err = create_map_eq(dev, &eq->core, ¶m);
839 if (err) {
840 kfree(eq);
841 goto clean;
842 }
843 err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb);
844 if (err) {
845 destroy_unmap_eq(dev, &eq->core);
846 kfree(eq);
847 goto clean;
848 }
849
850 mlx5_core_dbg(dev, "allocated completion EQN %d\n", eq->core.eqn);
851 /* add tail, to keep the list ordered, for mlx5_vector2eqn to work */
852 list_add_tail(&eq->list, &table->comp_eqs_list);
853 }
854
855 return 0;
856
857 clean:
858 destroy_comp_eqs(dev);
859 return err;
860 }
861
mlx5_vector2eqn(struct mlx5_core_dev * dev,int vector,int * eqn,unsigned int * irqn)862 int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn,
863 unsigned int *irqn)
864 {
865 struct mlx5_eq_table *table = dev->priv.eq_table;
866 struct mlx5_eq_comp *eq, *n;
867 int err = -ENOENT;
868 int i = 0;
869
870 list_for_each_entry_safe(eq, n, &table->comp_eqs_list, list) {
871 if (i++ == vector) {
872 *eqn = eq->core.eqn;
873 *irqn = eq->core.irqn;
874 err = 0;
875 break;
876 }
877 }
878
879 return err;
880 }
881 EXPORT_SYMBOL(mlx5_vector2eqn);
882
mlx5_comp_vectors_count(struct mlx5_core_dev * dev)883 unsigned int mlx5_comp_vectors_count(struct mlx5_core_dev *dev)
884 {
885 return dev->priv.eq_table->num_comp_eqs;
886 }
887 EXPORT_SYMBOL(mlx5_comp_vectors_count);
888
889 struct cpumask *
mlx5_comp_irq_get_affinity_mask(struct mlx5_core_dev * dev,int vector)890 mlx5_comp_irq_get_affinity_mask(struct mlx5_core_dev *dev, int vector)
891 {
892 int vecidx = vector + MLX5_IRQ_VEC_COMP_BASE;
893
894 return mlx5_irq_get_affinity_mask(dev->priv.eq_table->irq_table,
895 vecidx);
896 }
897 EXPORT_SYMBOL(mlx5_comp_irq_get_affinity_mask);
898
899 #ifdef CONFIG_RFS_ACCEL
mlx5_eq_table_get_rmap(struct mlx5_core_dev * dev)900 struct cpu_rmap *mlx5_eq_table_get_rmap(struct mlx5_core_dev *dev)
901 {
902 return mlx5_irq_get_rmap(dev->priv.eq_table->irq_table);
903 }
904 #endif
905
mlx5_eqn2comp_eq(struct mlx5_core_dev * dev,int eqn)906 struct mlx5_eq_comp *mlx5_eqn2comp_eq(struct mlx5_core_dev *dev, int eqn)
907 {
908 struct mlx5_eq_table *table = dev->priv.eq_table;
909 struct mlx5_eq_comp *eq;
910
911 list_for_each_entry(eq, &table->comp_eqs_list, list) {
912 if (eq->core.eqn == eqn)
913 return eq;
914 }
915
916 return ERR_PTR(-ENOENT);
917 }
918
919 /* This function should only be called after mlx5_cmd_force_teardown_hca */
mlx5_core_eq_free_irqs(struct mlx5_core_dev * dev)920 void mlx5_core_eq_free_irqs(struct mlx5_core_dev *dev)
921 {
922 struct mlx5_eq_table *table = dev->priv.eq_table;
923
924 mutex_lock(&table->lock); /* sync with create/destroy_async_eq */
925 mlx5_irq_table_destroy(dev);
926 mutex_unlock(&table->lock);
927 }
928
mlx5_eq_table_create(struct mlx5_core_dev * dev)929 int mlx5_eq_table_create(struct mlx5_core_dev *dev)
930 {
931 struct mlx5_eq_table *eq_table = dev->priv.eq_table;
932 int err;
933
934 eq_table->num_comp_eqs =
935 mlx5_irq_get_num_comp(eq_table->irq_table);
936
937 err = create_async_eqs(dev);
938 if (err) {
939 mlx5_core_err(dev, "Failed to create async EQs\n");
940 goto err_async_eqs;
941 }
942
943 err = create_comp_eqs(dev);
944 if (err) {
945 mlx5_core_err(dev, "Failed to create completion EQs\n");
946 goto err_comp_eqs;
947 }
948
949 return 0;
950 err_comp_eqs:
951 destroy_async_eqs(dev);
952 err_async_eqs:
953 return err;
954 }
955
mlx5_eq_table_destroy(struct mlx5_core_dev * dev)956 void mlx5_eq_table_destroy(struct mlx5_core_dev *dev)
957 {
958 destroy_comp_eqs(dev);
959 destroy_async_eqs(dev);
960 }
961
mlx5_eq_notifier_register(struct mlx5_core_dev * dev,struct mlx5_nb * nb)962 int mlx5_eq_notifier_register(struct mlx5_core_dev *dev, struct mlx5_nb *nb)
963 {
964 struct mlx5_eq_table *eqt = dev->priv.eq_table;
965
966 return atomic_notifier_chain_register(&eqt->nh[nb->event_type], &nb->nb);
967 }
968 EXPORT_SYMBOL(mlx5_eq_notifier_register);
969
mlx5_eq_notifier_unregister(struct mlx5_core_dev * dev,struct mlx5_nb * nb)970 int mlx5_eq_notifier_unregister(struct mlx5_core_dev *dev, struct mlx5_nb *nb)
971 {
972 struct mlx5_eq_table *eqt = dev->priv.eq_table;
973
974 return atomic_notifier_chain_unregister(&eqt->nh[nb->event_type], &nb->nb);
975 }
976 EXPORT_SYMBOL(mlx5_eq_notifier_unregister);
977