0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/kernel.h>
0034 #include <linux/hardirq.h>
0035 #include <linux/mlx5/driver.h>
0036 #include <rdma/ib_verbs.h>
0037 #include <linux/mlx5/cq.h>
0038 #include "mlx5_core.h"
0039 #include "lib/eq.h"
0040
0041 #define TASKLET_MAX_TIME 2
0042 #define TASKLET_MAX_TIME_JIFFIES msecs_to_jiffies(TASKLET_MAX_TIME)
0043
0044 void mlx5_cq_tasklet_cb(struct tasklet_struct *t)
0045 {
0046 unsigned long flags;
0047 unsigned long end = jiffies + TASKLET_MAX_TIME_JIFFIES;
0048 struct mlx5_eq_tasklet *ctx = from_tasklet(ctx, t, task);
0049 struct mlx5_core_cq *mcq;
0050 struct mlx5_core_cq *temp;
0051
0052 spin_lock_irqsave(&ctx->lock, flags);
0053 list_splice_tail_init(&ctx->list, &ctx->process_list);
0054 spin_unlock_irqrestore(&ctx->lock, flags);
0055
0056 list_for_each_entry_safe(mcq, temp, &ctx->process_list,
0057 tasklet_ctx.list) {
0058 list_del_init(&mcq->tasklet_ctx.list);
0059 mcq->tasklet_ctx.comp(mcq, NULL);
0060 mlx5_cq_put(mcq);
0061 if (time_after(jiffies, end))
0062 break;
0063 }
0064
0065 if (!list_empty(&ctx->process_list))
0066 tasklet_schedule(&ctx->task);
0067 }
0068
0069 static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
0070 struct mlx5_eqe *eqe)
0071 {
0072 unsigned long flags;
0073 struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
0074
0075 spin_lock_irqsave(&tasklet_ctx->lock, flags);
0076
0077
0078
0079
0080
0081 if (list_empty_careful(&cq->tasklet_ctx.list)) {
0082 mlx5_cq_hold(cq);
0083 list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list);
0084 }
0085 spin_unlock_irqrestore(&tasklet_ctx->lock, flags);
0086 }
0087
0088
0089 int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
0090 u32 *in, int inlen, u32 *out, int outlen)
0091 {
0092 int eqn = MLX5_GET(cqc, MLX5_ADDR_OF(create_cq_in, in, cq_context),
0093 c_eqn_or_apu_element);
0094 u32 din[MLX5_ST_SZ_DW(destroy_cq_in)] = {};
0095 struct mlx5_eq_comp *eq;
0096 int err;
0097
0098 eq = mlx5_eqn2comp_eq(dev, eqn);
0099 if (IS_ERR(eq))
0100 return PTR_ERR(eq);
0101
0102 memset(out, 0, outlen);
0103 MLX5_SET(create_cq_in, in, opcode, MLX5_CMD_OP_CREATE_CQ);
0104 err = mlx5_cmd_do(dev, in, inlen, out, outlen);
0105 if (err)
0106 return err;
0107
0108 cq->cqn = MLX5_GET(create_cq_out, out, cqn);
0109 cq->cons_index = 0;
0110 cq->arm_sn = 0;
0111 cq->eq = eq;
0112 cq->uid = MLX5_GET(create_cq_in, in, uid);
0113 refcount_set(&cq->refcount, 1);
0114 init_completion(&cq->free);
0115 if (!cq->comp)
0116 cq->comp = mlx5_add_cq_to_tasklet;
0117
0118 cq->tasklet_ctx.priv = &eq->tasklet_ctx;
0119 INIT_LIST_HEAD(&cq->tasklet_ctx.list);
0120
0121
0122 err = mlx5_eq_add_cq(&eq->core, cq);
0123 if (err)
0124 goto err_cmd;
0125
0126
0127 err = mlx5_eq_add_cq(mlx5_get_async_eq(dev), cq);
0128 if (err)
0129 goto err_cq_add;
0130
0131 cq->pid = current->pid;
0132 err = mlx5_debug_cq_add(dev, cq);
0133 if (err)
0134 mlx5_core_dbg(dev, "failed adding CP 0x%x to debug file system\n",
0135 cq->cqn);
0136
0137 cq->uar = dev->priv.uar;
0138 cq->irqn = eq->core.irqn;
0139
0140 return 0;
0141
0142 err_cq_add:
0143 mlx5_eq_del_cq(&eq->core, cq);
0144 err_cmd:
0145 MLX5_SET(destroy_cq_in, din, opcode, MLX5_CMD_OP_DESTROY_CQ);
0146 MLX5_SET(destroy_cq_in, din, cqn, cq->cqn);
0147 MLX5_SET(destroy_cq_in, din, uid, cq->uid);
0148 mlx5_cmd_exec_in(dev, destroy_cq, din);
0149 return err;
0150 }
0151 EXPORT_SYMBOL(mlx5_create_cq);
0152
0153
0154 int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
0155 u32 *in, int inlen, u32 *out, int outlen)
0156 {
0157 int err = mlx5_create_cq(dev, cq, in, inlen, out, outlen);
0158
0159 return mlx5_cmd_check(dev, err, in, out);
0160 }
0161 EXPORT_SYMBOL(mlx5_core_create_cq);
0162
0163 int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
0164 {
0165 u32 in[MLX5_ST_SZ_DW(destroy_cq_in)] = {};
0166 int err;
0167
0168 mlx5_debug_cq_remove(dev, cq);
0169
0170 mlx5_eq_del_cq(mlx5_get_async_eq(dev), cq);
0171 mlx5_eq_del_cq(&cq->eq->core, cq);
0172
0173 MLX5_SET(destroy_cq_in, in, opcode, MLX5_CMD_OP_DESTROY_CQ);
0174 MLX5_SET(destroy_cq_in, in, cqn, cq->cqn);
0175 MLX5_SET(destroy_cq_in, in, uid, cq->uid);
0176 err = mlx5_cmd_exec_in(dev, destroy_cq, in);
0177 if (err)
0178 return err;
0179
0180 synchronize_irq(cq->irqn);
0181 mlx5_cq_put(cq);
0182 wait_for_completion(&cq->free);
0183
0184 return 0;
0185 }
0186 EXPORT_SYMBOL(mlx5_core_destroy_cq);
0187
0188 int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
0189 u32 *out)
0190 {
0191 u32 in[MLX5_ST_SZ_DW(query_cq_in)] = {};
0192
0193 MLX5_SET(query_cq_in, in, opcode, MLX5_CMD_OP_QUERY_CQ);
0194 MLX5_SET(query_cq_in, in, cqn, cq->cqn);
0195 return mlx5_cmd_exec_inout(dev, query_cq, in, out);
0196 }
0197 EXPORT_SYMBOL(mlx5_core_query_cq);
0198
0199 int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
0200 u32 *in, int inlen)
0201 {
0202 u32 out[MLX5_ST_SZ_DW(modify_cq_out)] = {};
0203
0204 MLX5_SET(modify_cq_in, in, opcode, MLX5_CMD_OP_MODIFY_CQ);
0205 MLX5_SET(modify_cq_in, in, uid, cq->uid);
0206 return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
0207 }
0208 EXPORT_SYMBOL(mlx5_core_modify_cq);
0209
0210 int mlx5_core_modify_cq_moderation(struct mlx5_core_dev *dev,
0211 struct mlx5_core_cq *cq,
0212 u16 cq_period,
0213 u16 cq_max_count)
0214 {
0215 u32 in[MLX5_ST_SZ_DW(modify_cq_in)] = {};
0216 void *cqc;
0217
0218 MLX5_SET(modify_cq_in, in, cqn, cq->cqn);
0219 cqc = MLX5_ADDR_OF(modify_cq_in, in, cq_context);
0220 MLX5_SET(cqc, cqc, cq_period, cq_period);
0221 MLX5_SET(cqc, cqc, cq_max_count, cq_max_count);
0222 MLX5_SET(modify_cq_in, in,
0223 modify_field_select_resize_field_select.modify_field_select.modify_field_select,
0224 MLX5_CQ_MODIFY_PERIOD | MLX5_CQ_MODIFY_COUNT);
0225
0226 return mlx5_core_modify_cq(dev, cq, in, sizeof(in));
0227 }
0228 EXPORT_SYMBOL(mlx5_core_modify_cq_moderation);