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
0034 #include <linux/mlx4/qp.h>
0035 #include <linux/mlx4/srq.h>
0036 #include <linux/slab.h>
0037
0038 #include "mlx4_ib.h"
0039 #include <rdma/mlx4-abi.h>
0040 #include <rdma/uverbs_ioctl.h>
0041
0042 static void *get_wqe(struct mlx4_ib_srq *srq, int n)
0043 {
0044 return mlx4_buf_offset(&srq->buf, n << srq->msrq.wqe_shift);
0045 }
0046
0047 static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type)
0048 {
0049 struct ib_event event;
0050 struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
0051
0052 if (ibsrq->event_handler) {
0053 event.device = ibsrq->device;
0054 event.element.srq = ibsrq;
0055 switch (type) {
0056 case MLX4_EVENT_TYPE_SRQ_LIMIT:
0057 event.event = IB_EVENT_SRQ_LIMIT_REACHED;
0058 break;
0059 case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
0060 event.event = IB_EVENT_SRQ_ERR;
0061 break;
0062 default:
0063 pr_warn("Unexpected event type %d "
0064 "on SRQ %06x\n", type, srq->srqn);
0065 return;
0066 }
0067
0068 ibsrq->event_handler(&event, ibsrq->srq_context);
0069 }
0070 }
0071
0072 int mlx4_ib_create_srq(struct ib_srq *ib_srq,
0073 struct ib_srq_init_attr *init_attr,
0074 struct ib_udata *udata)
0075 {
0076 struct mlx4_ib_dev *dev = to_mdev(ib_srq->device);
0077 struct mlx4_ib_ucontext *ucontext = rdma_udata_to_drv_context(
0078 udata, struct mlx4_ib_ucontext, ibucontext);
0079 struct mlx4_ib_srq *srq = to_msrq(ib_srq);
0080 struct mlx4_wqe_srq_next_seg *next;
0081 struct mlx4_wqe_data_seg *scatter;
0082 u32 cqn;
0083 u16 xrcdn;
0084 int desc_size;
0085 int buf_size;
0086 int err;
0087 int i;
0088
0089 if (init_attr->srq_type != IB_SRQT_BASIC &&
0090 init_attr->srq_type != IB_SRQT_XRC)
0091 return -EOPNOTSUPP;
0092
0093
0094 if (init_attr->attr.max_wr >= dev->dev->caps.max_srq_wqes ||
0095 init_attr->attr.max_sge > dev->dev->caps.max_srq_sge)
0096 return -EINVAL;
0097
0098 mutex_init(&srq->mutex);
0099 spin_lock_init(&srq->lock);
0100 srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1);
0101 srq->msrq.max_gs = init_attr->attr.max_sge;
0102
0103 desc_size = max(32UL,
0104 roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) +
0105 srq->msrq.max_gs *
0106 sizeof (struct mlx4_wqe_data_seg)));
0107 srq->msrq.wqe_shift = ilog2(desc_size);
0108
0109 buf_size = srq->msrq.max * desc_size;
0110
0111 if (udata) {
0112 struct mlx4_ib_create_srq ucmd;
0113
0114 if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
0115 return -EFAULT;
0116
0117 srq->umem =
0118 ib_umem_get(ib_srq->device, ucmd.buf_addr, buf_size, 0);
0119 if (IS_ERR(srq->umem))
0120 return PTR_ERR(srq->umem);
0121
0122 err = mlx4_mtt_init(
0123 dev->dev, ib_umem_num_dma_blocks(srq->umem, PAGE_SIZE),
0124 PAGE_SHIFT, &srq->mtt);
0125 if (err)
0126 goto err_buf;
0127
0128 err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem);
0129 if (err)
0130 goto err_mtt;
0131
0132 err = mlx4_ib_db_map_user(udata, ucmd.db_addr, &srq->db);
0133 if (err)
0134 goto err_mtt;
0135 } else {
0136 err = mlx4_db_alloc(dev->dev, &srq->db, 0);
0137 if (err)
0138 return err;
0139
0140 *srq->db.db = 0;
0141
0142 if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2,
0143 &srq->buf)) {
0144 err = -ENOMEM;
0145 goto err_db;
0146 }
0147
0148 srq->head = 0;
0149 srq->tail = srq->msrq.max - 1;
0150 srq->wqe_ctr = 0;
0151
0152 for (i = 0; i < srq->msrq.max; ++i) {
0153 next = get_wqe(srq, i);
0154 next->next_wqe_index =
0155 cpu_to_be16((i + 1) & (srq->msrq.max - 1));
0156
0157 for (scatter = (void *) (next + 1);
0158 (void *) scatter < (void *) next + desc_size;
0159 ++scatter)
0160 scatter->lkey = cpu_to_be32(MLX4_INVALID_LKEY);
0161 }
0162
0163 err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift,
0164 &srq->mtt);
0165 if (err)
0166 goto err_buf;
0167
0168 err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf);
0169 if (err)
0170 goto err_mtt;
0171
0172 srq->wrid = kvmalloc_array(srq->msrq.max,
0173 sizeof(u64), GFP_KERNEL);
0174 if (!srq->wrid) {
0175 err = -ENOMEM;
0176 goto err_mtt;
0177 }
0178 }
0179
0180 cqn = ib_srq_has_cq(init_attr->srq_type) ?
0181 to_mcq(init_attr->ext.cq)->mcq.cqn : 0;
0182 xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ?
0183 to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn :
0184 (u16) dev->dev->caps.reserved_xrcds;
0185 err = mlx4_srq_alloc(dev->dev, to_mpd(ib_srq->pd)->pdn, cqn, xrcdn,
0186 &srq->mtt, srq->db.dma, &srq->msrq);
0187 if (err)
0188 goto err_wrid;
0189
0190 srq->msrq.event = mlx4_ib_srq_event;
0191 srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
0192
0193 if (udata)
0194 if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) {
0195 err = -EFAULT;
0196 goto err_wrid;
0197 }
0198
0199 init_attr->attr.max_wr = srq->msrq.max - 1;
0200
0201 return 0;
0202
0203 err_wrid:
0204 if (udata)
0205 mlx4_ib_db_unmap_user(ucontext, &srq->db);
0206 else
0207 kvfree(srq->wrid);
0208
0209 err_mtt:
0210 mlx4_mtt_cleanup(dev->dev, &srq->mtt);
0211
0212 err_buf:
0213 if (!srq->umem)
0214 mlx4_buf_free(dev->dev, buf_size, &srq->buf);
0215 ib_umem_release(srq->umem);
0216
0217 err_db:
0218 if (!udata)
0219 mlx4_db_free(dev->dev, &srq->db);
0220
0221 return err;
0222 }
0223
0224 int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
0225 enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
0226 {
0227 struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
0228 struct mlx4_ib_srq *srq = to_msrq(ibsrq);
0229 int ret;
0230
0231
0232 if (attr_mask & IB_SRQ_MAX_WR)
0233 return -EINVAL;
0234
0235 if (attr_mask & IB_SRQ_LIMIT) {
0236 if (attr->srq_limit >= srq->msrq.max)
0237 return -EINVAL;
0238
0239 mutex_lock(&srq->mutex);
0240 ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit);
0241 mutex_unlock(&srq->mutex);
0242
0243 if (ret)
0244 return ret;
0245 }
0246
0247 return 0;
0248 }
0249
0250 int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
0251 {
0252 struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
0253 struct mlx4_ib_srq *srq = to_msrq(ibsrq);
0254 int ret;
0255 int limit_watermark;
0256
0257 ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark);
0258 if (ret)
0259 return ret;
0260
0261 srq_attr->srq_limit = limit_watermark;
0262 srq_attr->max_wr = srq->msrq.max - 1;
0263 srq_attr->max_sge = srq->msrq.max_gs;
0264
0265 return 0;
0266 }
0267
0268 int mlx4_ib_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
0269 {
0270 struct mlx4_ib_dev *dev = to_mdev(srq->device);
0271 struct mlx4_ib_srq *msrq = to_msrq(srq);
0272
0273 mlx4_srq_free(dev->dev, &msrq->msrq);
0274 mlx4_mtt_cleanup(dev->dev, &msrq->mtt);
0275
0276 if (udata) {
0277 mlx4_ib_db_unmap_user(
0278 rdma_udata_to_drv_context(
0279 udata,
0280 struct mlx4_ib_ucontext,
0281 ibucontext),
0282 &msrq->db);
0283 } else {
0284 kvfree(msrq->wrid);
0285 mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
0286 &msrq->buf);
0287 mlx4_db_free(dev->dev, &msrq->db);
0288 }
0289 ib_umem_release(msrq->umem);
0290 return 0;
0291 }
0292
0293 void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index)
0294 {
0295 struct mlx4_wqe_srq_next_seg *next;
0296
0297
0298 spin_lock(&srq->lock);
0299
0300 next = get_wqe(srq, srq->tail);
0301 next->next_wqe_index = cpu_to_be16(wqe_index);
0302 srq->tail = wqe_index;
0303
0304 spin_unlock(&srq->lock);
0305 }
0306
0307 int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
0308 const struct ib_recv_wr **bad_wr)
0309 {
0310 struct mlx4_ib_srq *srq = to_msrq(ibsrq);
0311 struct mlx4_wqe_srq_next_seg *next;
0312 struct mlx4_wqe_data_seg *scat;
0313 unsigned long flags;
0314 int err = 0;
0315 int nreq;
0316 int i;
0317 struct mlx4_ib_dev *mdev = to_mdev(ibsrq->device);
0318
0319 spin_lock_irqsave(&srq->lock, flags);
0320 if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
0321 err = -EIO;
0322 *bad_wr = wr;
0323 goto out;
0324 }
0325
0326 for (nreq = 0; wr; ++nreq, wr = wr->next) {
0327 if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
0328 err = -EINVAL;
0329 *bad_wr = wr;
0330 break;
0331 }
0332
0333 if (unlikely(srq->head == srq->tail)) {
0334 err = -ENOMEM;
0335 *bad_wr = wr;
0336 break;
0337 }
0338
0339 srq->wrid[srq->head] = wr->wr_id;
0340
0341 next = get_wqe(srq, srq->head);
0342 srq->head = be16_to_cpu(next->next_wqe_index);
0343 scat = (struct mlx4_wqe_data_seg *) (next + 1);
0344
0345 for (i = 0; i < wr->num_sge; ++i) {
0346 scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
0347 scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey);
0348 scat[i].addr = cpu_to_be64(wr->sg_list[i].addr);
0349 }
0350
0351 if (i < srq->msrq.max_gs) {
0352 scat[i].byte_count = 0;
0353 scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY);
0354 scat[i].addr = 0;
0355 }
0356 }
0357
0358 if (likely(nreq)) {
0359 srq->wqe_ctr += nreq;
0360
0361
0362
0363
0364
0365 wmb();
0366
0367 *srq->db.db = cpu_to_be32(srq->wqe_ctr);
0368 }
0369 out:
0370
0371 spin_unlock_irqrestore(&srq->lock, flags);
0372
0373 return err;
0374 }