cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mthca_srq.c (17457B)


      1/*
      2 * Copyright (c) 2005 Cisco Systems. 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/slab.h>
     34#include <linux/string.h>
     35#include <linux/sched.h>
     36
     37#include <asm/io.h>
     38
     39#include <rdma/uverbs_ioctl.h>
     40
     41#include "mthca_dev.h"
     42#include "mthca_cmd.h"
     43#include "mthca_memfree.h"
     44#include "mthca_wqe.h"
     45
     46enum {
     47	MTHCA_MAX_DIRECT_SRQ_SIZE = 4 * PAGE_SIZE
     48};
     49
     50struct mthca_tavor_srq_context {
     51	__be64 wqe_base_ds;	/* low 6 bits is descriptor size */
     52	__be32 state_pd;
     53	__be32 lkey;
     54	__be32 uar;
     55	__be16 limit_watermark;
     56	__be16 wqe_cnt;
     57	u32    reserved[2];
     58};
     59
     60struct mthca_arbel_srq_context {
     61	__be32 state_logsize_srqn;
     62	__be32 lkey;
     63	__be32 db_index;
     64	__be32 logstride_usrpage;
     65	__be64 wqe_base;
     66	__be32 eq_pd;
     67	__be16 limit_watermark;
     68	__be16 wqe_cnt;
     69	u16    reserved1;
     70	__be16 wqe_counter;
     71	u32    reserved2[3];
     72};
     73
     74static void *get_wqe(struct mthca_srq *srq, int n)
     75{
     76	if (srq->is_direct)
     77		return srq->queue.direct.buf + (n << srq->wqe_shift);
     78	else
     79		return srq->queue.page_list[(n << srq->wqe_shift) >> PAGE_SHIFT].buf +
     80			((n << srq->wqe_shift) & (PAGE_SIZE - 1));
     81}
     82
     83/*
     84 * Return a pointer to the location within a WQE that we're using as a
     85 * link when the WQE is in the free list.  We use the imm field
     86 * because in the Tavor case, posting a WQE may overwrite the next
     87 * segment of the previous WQE, but a receive WQE will never touch the
     88 * imm field.  This avoids corrupting our free list if the previous
     89 * WQE has already completed and been put on the free list when we
     90 * post the next WQE.
     91 */
     92static inline int *wqe_to_link(void *wqe)
     93{
     94	return (int *) (wqe + offsetof(struct mthca_next_seg, imm));
     95}
     96
     97static void mthca_tavor_init_srq_context(struct mthca_dev *dev,
     98					 struct mthca_pd *pd,
     99					 struct mthca_srq *srq,
    100					 struct mthca_tavor_srq_context *context,
    101					 struct ib_udata *udata)
    102{
    103	struct mthca_ucontext *ucontext = rdma_udata_to_drv_context(
    104		udata, struct mthca_ucontext, ibucontext);
    105
    106	memset(context, 0, sizeof *context);
    107
    108	context->wqe_base_ds = cpu_to_be64(1 << (srq->wqe_shift - 4));
    109	context->state_pd    = cpu_to_be32(pd->pd_num);
    110	context->lkey        = cpu_to_be32(srq->mr.ibmr.lkey);
    111
    112	if (udata)
    113		context->uar = cpu_to_be32(ucontext->uar.index);
    114	else
    115		context->uar = cpu_to_be32(dev->driver_uar.index);
    116}
    117
    118static void mthca_arbel_init_srq_context(struct mthca_dev *dev,
    119					 struct mthca_pd *pd,
    120					 struct mthca_srq *srq,
    121					 struct mthca_arbel_srq_context *context,
    122					 struct ib_udata *udata)
    123{
    124	struct mthca_ucontext *ucontext = rdma_udata_to_drv_context(
    125		udata, struct mthca_ucontext, ibucontext);
    126	int logsize, max;
    127
    128	memset(context, 0, sizeof *context);
    129
    130	/*
    131	 * Put max in a temporary variable to work around gcc bug
    132	 * triggered by ilog2() on sparc64.
    133	 */
    134	max = srq->max;
    135	logsize = ilog2(max);
    136	context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn);
    137	context->lkey = cpu_to_be32(srq->mr.ibmr.lkey);
    138	context->db_index = cpu_to_be32(srq->db_index);
    139	context->logstride_usrpage = cpu_to_be32((srq->wqe_shift - 4) << 29);
    140	if (udata)
    141		context->logstride_usrpage |= cpu_to_be32(ucontext->uar.index);
    142	else
    143		context->logstride_usrpage |= cpu_to_be32(dev->driver_uar.index);
    144	context->eq_pd = cpu_to_be32(MTHCA_EQ_ASYNC << 24 | pd->pd_num);
    145}
    146
    147static void mthca_free_srq_buf(struct mthca_dev *dev, struct mthca_srq *srq)
    148{
    149	mthca_buf_free(dev, srq->max << srq->wqe_shift, &srq->queue,
    150		       srq->is_direct, &srq->mr);
    151	kfree(srq->wrid);
    152}
    153
    154static int mthca_alloc_srq_buf(struct mthca_dev *dev, struct mthca_pd *pd,
    155			       struct mthca_srq *srq, struct ib_udata *udata)
    156{
    157	struct mthca_data_seg *scatter;
    158	void *wqe;
    159	int err;
    160	int i;
    161
    162	if (udata)
    163		return 0;
    164
    165	srq->wrid = kmalloc_array(srq->max, sizeof(u64), GFP_KERNEL);
    166	if (!srq->wrid)
    167		return -ENOMEM;
    168
    169	err = mthca_buf_alloc(dev, srq->max << srq->wqe_shift,
    170			      MTHCA_MAX_DIRECT_SRQ_SIZE,
    171			      &srq->queue, &srq->is_direct, pd, 1, &srq->mr);
    172	if (err) {
    173		kfree(srq->wrid);
    174		return err;
    175	}
    176
    177	/*
    178	 * Now initialize the SRQ buffer so that all of the WQEs are
    179	 * linked into the list of free WQEs.  In addition, set the
    180	 * scatter list L_Keys to the sentry value of 0x100.
    181	 */
    182	for (i = 0; i < srq->max; ++i) {
    183		struct mthca_next_seg *next;
    184
    185		next = wqe = get_wqe(srq, i);
    186
    187		if (i < srq->max - 1) {
    188			*wqe_to_link(wqe) = i + 1;
    189			next->nda_op = htonl(((i + 1) << srq->wqe_shift) | 1);
    190		} else {
    191			*wqe_to_link(wqe) = -1;
    192			next->nda_op = 0;
    193		}
    194
    195		for (scatter = wqe + sizeof (struct mthca_next_seg);
    196		     (void *) scatter < wqe + (1 << srq->wqe_shift);
    197		     ++scatter)
    198			scatter->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
    199	}
    200
    201	srq->last = get_wqe(srq, srq->max - 1);
    202
    203	return 0;
    204}
    205
    206int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
    207		    struct ib_srq_attr *attr, struct mthca_srq *srq,
    208		    struct ib_udata *udata)
    209{
    210	struct mthca_mailbox *mailbox;
    211	int ds;
    212	int err;
    213
    214	/* Sanity check SRQ size before proceeding */
    215	if (attr->max_wr  > dev->limits.max_srq_wqes ||
    216	    attr->max_sge > dev->limits.max_srq_sge)
    217		return -EINVAL;
    218
    219	srq->max      = attr->max_wr;
    220	srq->max_gs   = attr->max_sge;
    221	srq->counter  = 0;
    222
    223	if (mthca_is_memfree(dev))
    224		srq->max = roundup_pow_of_two(srq->max + 1);
    225	else
    226		srq->max = srq->max + 1;
    227
    228	ds = max(64UL,
    229		 roundup_pow_of_two(sizeof (struct mthca_next_seg) +
    230				    srq->max_gs * sizeof (struct mthca_data_seg)));
    231
    232	if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz))
    233		return -EINVAL;
    234
    235	srq->wqe_shift = ilog2(ds);
    236
    237	srq->srqn = mthca_alloc(&dev->srq_table.alloc);
    238	if (srq->srqn == -1)
    239		return -ENOMEM;
    240
    241	if (mthca_is_memfree(dev)) {
    242		err = mthca_table_get(dev, dev->srq_table.table, srq->srqn);
    243		if (err)
    244			goto err_out;
    245
    246		if (!udata) {
    247			srq->db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SRQ,
    248						       srq->srqn, &srq->db);
    249			if (srq->db_index < 0) {
    250				err = -ENOMEM;
    251				goto err_out_icm;
    252			}
    253		}
    254	}
    255
    256	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
    257	if (IS_ERR(mailbox)) {
    258		err = PTR_ERR(mailbox);
    259		goto err_out_db;
    260	}
    261
    262	err = mthca_alloc_srq_buf(dev, pd, srq, udata);
    263	if (err)
    264		goto err_out_mailbox;
    265
    266	spin_lock_init(&srq->lock);
    267	srq->refcount = 1;
    268	init_waitqueue_head(&srq->wait);
    269	mutex_init(&srq->mutex);
    270
    271	if (mthca_is_memfree(dev))
    272		mthca_arbel_init_srq_context(dev, pd, srq, mailbox->buf, udata);
    273	else
    274		mthca_tavor_init_srq_context(dev, pd, srq, mailbox->buf, udata);
    275
    276	err = mthca_SW2HW_SRQ(dev, mailbox, srq->srqn);
    277
    278	if (err) {
    279		mthca_warn(dev, "SW2HW_SRQ failed (%d)\n", err);
    280		goto err_out_free_buf;
    281	}
    282
    283	spin_lock_irq(&dev->srq_table.lock);
    284	if (mthca_array_set(&dev->srq_table.srq,
    285			    srq->srqn & (dev->limits.num_srqs - 1),
    286			    srq)) {
    287		spin_unlock_irq(&dev->srq_table.lock);
    288		goto err_out_free_srq;
    289	}
    290	spin_unlock_irq(&dev->srq_table.lock);
    291
    292	mthca_free_mailbox(dev, mailbox);
    293
    294	srq->first_free = 0;
    295	srq->last_free  = srq->max - 1;
    296
    297	attr->max_wr    = srq->max - 1;
    298	attr->max_sge   = srq->max_gs;
    299
    300	return 0;
    301
    302err_out_free_srq:
    303	err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn);
    304	if (err)
    305		mthca_warn(dev, "HW2SW_SRQ failed (%d)\n", err);
    306
    307err_out_free_buf:
    308	if (!udata)
    309		mthca_free_srq_buf(dev, srq);
    310
    311err_out_mailbox:
    312	mthca_free_mailbox(dev, mailbox);
    313
    314err_out_db:
    315	if (!udata && mthca_is_memfree(dev))
    316		mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index);
    317
    318err_out_icm:
    319	mthca_table_put(dev, dev->srq_table.table, srq->srqn);
    320
    321err_out:
    322	mthca_free(&dev->srq_table.alloc, srq->srqn);
    323
    324	return err;
    325}
    326
    327static inline int get_srq_refcount(struct mthca_dev *dev, struct mthca_srq *srq)
    328{
    329	int c;
    330
    331	spin_lock_irq(&dev->srq_table.lock);
    332	c = srq->refcount;
    333	spin_unlock_irq(&dev->srq_table.lock);
    334
    335	return c;
    336}
    337
    338void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
    339{
    340	struct mthca_mailbox *mailbox;
    341	int err;
    342
    343	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
    344	if (IS_ERR(mailbox)) {
    345		mthca_warn(dev, "No memory for mailbox to free SRQ.\n");
    346		return;
    347	}
    348
    349	err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn);
    350	if (err)
    351		mthca_warn(dev, "HW2SW_SRQ failed (%d)\n", err);
    352
    353	spin_lock_irq(&dev->srq_table.lock);
    354	mthca_array_clear(&dev->srq_table.srq,
    355			  srq->srqn & (dev->limits.num_srqs - 1));
    356	--srq->refcount;
    357	spin_unlock_irq(&dev->srq_table.lock);
    358
    359	wait_event(srq->wait, !get_srq_refcount(dev, srq));
    360
    361	if (!srq->ibsrq.uobject) {
    362		mthca_free_srq_buf(dev, srq);
    363		if (mthca_is_memfree(dev))
    364			mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index);
    365	}
    366
    367	mthca_table_put(dev, dev->srq_table.table, srq->srqn);
    368	mthca_free(&dev->srq_table.alloc, srq->srqn);
    369	mthca_free_mailbox(dev, mailbox);
    370}
    371
    372int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
    373		     enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
    374{
    375	struct mthca_dev *dev = to_mdev(ibsrq->device);
    376	struct mthca_srq *srq = to_msrq(ibsrq);
    377	int ret = 0;
    378
    379	/* We don't support resizing SRQs (yet?) */
    380	if (attr_mask & IB_SRQ_MAX_WR)
    381		return -EINVAL;
    382
    383	if (attr_mask & IB_SRQ_LIMIT) {
    384		u32 max_wr = mthca_is_memfree(dev) ? srq->max - 1 : srq->max;
    385		if (attr->srq_limit > max_wr)
    386			return -EINVAL;
    387
    388		mutex_lock(&srq->mutex);
    389		ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit);
    390		mutex_unlock(&srq->mutex);
    391	}
    392
    393	return ret;
    394}
    395
    396int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
    397{
    398	struct mthca_dev *dev = to_mdev(ibsrq->device);
    399	struct mthca_srq *srq = to_msrq(ibsrq);
    400	struct mthca_mailbox *mailbox;
    401	struct mthca_arbel_srq_context *arbel_ctx;
    402	struct mthca_tavor_srq_context *tavor_ctx;
    403	int err;
    404
    405	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
    406	if (IS_ERR(mailbox))
    407		return PTR_ERR(mailbox);
    408
    409	err = mthca_QUERY_SRQ(dev, srq->srqn, mailbox);
    410	if (err)
    411		goto out;
    412
    413	if (mthca_is_memfree(dev)) {
    414		arbel_ctx = mailbox->buf;
    415		srq_attr->srq_limit = be16_to_cpu(arbel_ctx->limit_watermark);
    416	} else {
    417		tavor_ctx = mailbox->buf;
    418		srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark);
    419	}
    420
    421	srq_attr->max_wr  = srq->max - 1;
    422	srq_attr->max_sge = srq->max_gs;
    423
    424out:
    425	mthca_free_mailbox(dev, mailbox);
    426
    427	return err;
    428}
    429
    430void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
    431		     enum ib_event_type event_type)
    432{
    433	struct mthca_srq *srq;
    434	struct ib_event event;
    435
    436	spin_lock(&dev->srq_table.lock);
    437	srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1));
    438	if (srq)
    439		++srq->refcount;
    440	spin_unlock(&dev->srq_table.lock);
    441
    442	if (!srq) {
    443		mthca_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
    444		return;
    445	}
    446
    447	if (!srq->ibsrq.event_handler)
    448		goto out;
    449
    450	event.device      = &dev->ib_dev;
    451	event.event       = event_type;
    452	event.element.srq = &srq->ibsrq;
    453	srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context);
    454
    455out:
    456	spin_lock(&dev->srq_table.lock);
    457	if (!--srq->refcount)
    458		wake_up(&srq->wait);
    459	spin_unlock(&dev->srq_table.lock);
    460}
    461
    462/*
    463 * This function must be called with IRQs disabled.
    464 */
    465void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr)
    466{
    467	int ind;
    468	struct mthca_next_seg *last_free;
    469
    470	ind = wqe_addr >> srq->wqe_shift;
    471
    472	spin_lock(&srq->lock);
    473
    474	last_free = get_wqe(srq, srq->last_free);
    475	*wqe_to_link(last_free) = ind;
    476	last_free->nda_op = htonl((ind << srq->wqe_shift) | 1);
    477	*wqe_to_link(get_wqe(srq, ind)) = -1;
    478	srq->last_free = ind;
    479
    480	spin_unlock(&srq->lock);
    481}
    482
    483int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
    484			      const struct ib_recv_wr **bad_wr)
    485{
    486	struct mthca_dev *dev = to_mdev(ibsrq->device);
    487	struct mthca_srq *srq = to_msrq(ibsrq);
    488	unsigned long flags;
    489	int err = 0;
    490	int first_ind;
    491	int ind;
    492	int next_ind;
    493	int nreq;
    494	int i;
    495	void *wqe;
    496	void *prev_wqe;
    497
    498	spin_lock_irqsave(&srq->lock, flags);
    499
    500	first_ind = srq->first_free;
    501
    502	for (nreq = 0; wr; wr = wr->next) {
    503		ind       = srq->first_free;
    504		wqe       = get_wqe(srq, ind);
    505		next_ind  = *wqe_to_link(wqe);
    506
    507		if (unlikely(next_ind < 0)) {
    508			mthca_err(dev, "SRQ %06x full\n", srq->srqn);
    509			err = -ENOMEM;
    510			*bad_wr = wr;
    511			break;
    512		}
    513
    514		prev_wqe  = srq->last;
    515		srq->last = wqe;
    516
    517		((struct mthca_next_seg *) wqe)->ee_nds = 0;
    518		/* flags field will always remain 0 */
    519
    520		wqe += sizeof (struct mthca_next_seg);
    521
    522		if (unlikely(wr->num_sge > srq->max_gs)) {
    523			err = -EINVAL;
    524			*bad_wr = wr;
    525			srq->last = prev_wqe;
    526			break;
    527		}
    528
    529		for (i = 0; i < wr->num_sge; ++i) {
    530			mthca_set_data_seg(wqe, wr->sg_list + i);
    531			wqe += sizeof (struct mthca_data_seg);
    532		}
    533
    534		if (i < srq->max_gs)
    535			mthca_set_data_seg_inval(wqe);
    536
    537		((struct mthca_next_seg *) prev_wqe)->ee_nds =
    538			cpu_to_be32(MTHCA_NEXT_DBD);
    539
    540		srq->wrid[ind]  = wr->wr_id;
    541		srq->first_free = next_ind;
    542
    543		++nreq;
    544		if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
    545			nreq = 0;
    546
    547			/*
    548			 * Make sure that descriptors are written
    549			 * before doorbell is rung.
    550			 */
    551			wmb();
    552
    553			mthca_write64(first_ind << srq->wqe_shift, srq->srqn << 8,
    554				      dev->kar + MTHCA_RECEIVE_DOORBELL,
    555				      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
    556
    557			first_ind = srq->first_free;
    558		}
    559	}
    560
    561	if (likely(nreq)) {
    562		/*
    563		 * Make sure that descriptors are written before
    564		 * doorbell is rung.
    565		 */
    566		wmb();
    567
    568		mthca_write64(first_ind << srq->wqe_shift, (srq->srqn << 8) | nreq,
    569			      dev->kar + MTHCA_RECEIVE_DOORBELL,
    570			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
    571	}
    572
    573	spin_unlock_irqrestore(&srq->lock, flags);
    574	return err;
    575}
    576
    577int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
    578			      const struct ib_recv_wr **bad_wr)
    579{
    580	struct mthca_dev *dev = to_mdev(ibsrq->device);
    581	struct mthca_srq *srq = to_msrq(ibsrq);
    582	unsigned long flags;
    583	int err = 0;
    584	int ind;
    585	int next_ind;
    586	int nreq;
    587	int i;
    588	void *wqe;
    589
    590	spin_lock_irqsave(&srq->lock, flags);
    591
    592	for (nreq = 0; wr; ++nreq, wr = wr->next) {
    593		ind       = srq->first_free;
    594		wqe       = get_wqe(srq, ind);
    595		next_ind  = *wqe_to_link(wqe);
    596
    597		if (unlikely(next_ind < 0)) {
    598			mthca_err(dev, "SRQ %06x full\n", srq->srqn);
    599			err = -ENOMEM;
    600			*bad_wr = wr;
    601			break;
    602		}
    603
    604		((struct mthca_next_seg *) wqe)->ee_nds = 0;
    605		/* flags field will always remain 0 */
    606
    607		wqe += sizeof (struct mthca_next_seg);
    608
    609		if (unlikely(wr->num_sge > srq->max_gs)) {
    610			err = -EINVAL;
    611			*bad_wr = wr;
    612			break;
    613		}
    614
    615		for (i = 0; i < wr->num_sge; ++i) {
    616			mthca_set_data_seg(wqe, wr->sg_list + i);
    617			wqe += sizeof (struct mthca_data_seg);
    618		}
    619
    620		if (i < srq->max_gs)
    621			mthca_set_data_seg_inval(wqe);
    622
    623		srq->wrid[ind]  = wr->wr_id;
    624		srq->first_free = next_ind;
    625	}
    626
    627	if (likely(nreq)) {
    628		srq->counter += nreq;
    629
    630		/*
    631		 * Make sure that descriptors are written before
    632		 * we write doorbell record.
    633		 */
    634		wmb();
    635		*srq->db = cpu_to_be32(srq->counter);
    636	}
    637
    638	spin_unlock_irqrestore(&srq->lock, flags);
    639	return err;
    640}
    641
    642int mthca_max_srq_sge(struct mthca_dev *dev)
    643{
    644	if (mthca_is_memfree(dev))
    645		return dev->limits.max_sg;
    646
    647	/*
    648	 * SRQ allocations are based on powers of 2 for Tavor,
    649	 * (although they only need to be multiples of 16 bytes).
    650	 *
    651	 * Therefore, we need to base the max number of sg entries on
    652	 * the largest power of 2 descriptor size that is <= to the
    653	 * actual max WQE descriptor size, rather than return the
    654	 * max_sg value given by the firmware (which is based on WQE
    655	 * sizes as multiples of 16, not powers of 2).
    656	 *
    657	 * If SRQ implementation is changed for Tavor to be based on
    658	 * multiples of 16, the calculation below can be deleted and
    659	 * the FW max_sg value returned.
    660	 */
    661	return min_t(int, dev->limits.max_sg,
    662		     ((1 << (fls(dev->limits.max_desc_sz) - 1)) -
    663		      sizeof (struct mthca_next_seg)) /
    664		     sizeof (struct mthca_data_seg));
    665}
    666
    667int mthca_init_srq_table(struct mthca_dev *dev)
    668{
    669	int err;
    670
    671	if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
    672		return 0;
    673
    674	spin_lock_init(&dev->srq_table.lock);
    675
    676	err = mthca_alloc_init(&dev->srq_table.alloc,
    677			       dev->limits.num_srqs,
    678			       dev->limits.num_srqs - 1,
    679			       dev->limits.reserved_srqs);
    680	if (err)
    681		return err;
    682
    683	err = mthca_array_init(&dev->srq_table.srq,
    684			       dev->limits.num_srqs);
    685	if (err)
    686		mthca_alloc_cleanup(&dev->srq_table.alloc);
    687
    688	return err;
    689}
    690
    691void mthca_cleanup_srq_table(struct mthca_dev *dev)
    692{
    693	if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
    694		return;
    695
    696	mthca_array_cleanup(&dev->srq_table.srq, dev->limits.num_srqs);
    697	mthca_alloc_cleanup(&dev->srq_table.alloc);
    698}