Exemplo n.º 1
0
Arquivo: cq.c Projeto: avagin/linux
int c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
{
	struct c4iw_cq *chp;
	struct c4iw_ucontext *ucontext;

	pr_debug("ib_cq %p\n", ib_cq);
	chp = to_c4iw_cq(ib_cq);

	xa_erase_irq(&chp->rhp->cqs, chp->cq.cqid);
	atomic_dec(&chp->refcnt);
	wait_event(chp->wait, !atomic_read(&chp->refcnt));

	ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext,
					     ibucontext);
	destroy_cq(&chp->rhp->rdev, &chp->cq,
		   ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx,
		   chp->destroy_skb, chp->wr_waitp);
	c4iw_put_wr_wait(chp->wr_waitp);
	kfree(chp);
	return 0;
}
Exemplo n.º 2
0
int c4iw_destroy_cq(struct ib_cq *ib_cq)
{
	struct c4iw_cq *chp;
	struct c4iw_ucontext *ucontext;

	pr_debug("ib_cq %p\n", ib_cq);
	chp = to_c4iw_cq(ib_cq);

	remove_handle(chp->rhp, &chp->rhp->cqidr, chp->cq.cqid);
	atomic_dec(&chp->refcnt);
	wait_event(chp->wait, !atomic_read(&chp->refcnt));

	ucontext = ib_cq->uobject ? to_c4iw_ucontext(ib_cq->uobject->context)
				  : NULL;
	destroy_cq(&chp->rhp->rdev, &chp->cq,
		   ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx,
		   chp->destroy_skb, chp->wr_waitp);
	c4iw_put_wr_wait(chp->wr_waitp);
	kfree(chp);
	return 0;
}
Exemplo n.º 3
0
Arquivo: cq.c Projeto: avagin/linux
struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
			     const struct ib_cq_init_attr *attr,
			     struct ib_udata *udata)
{
	int entries = attr->cqe;
	int vector = attr->comp_vector;
	struct c4iw_dev *rhp;
	struct c4iw_cq *chp;
	struct c4iw_create_cq ucmd;
	struct c4iw_create_cq_resp uresp;
	int ret, wr_len;
	size_t memsize, hwentries;
	struct c4iw_mm_entry *mm, *mm2;
	struct c4iw_ucontext *ucontext = rdma_udata_to_drv_context(
		udata, struct c4iw_ucontext, ibucontext);

	pr_debug("ib_dev %p entries %d\n", ibdev, entries);
	if (attr->flags)
		return ERR_PTR(-EINVAL);

	rhp = to_c4iw_dev(ibdev);

	if (vector >= rhp->rdev.lldi.nciq)
		return ERR_PTR(-EINVAL);

	if (udata) {
		if (udata->inlen < sizeof(ucmd))
			ucontext->is_32b_cqe = 1;
	}

	chp = kzalloc(sizeof(*chp), GFP_KERNEL);
	if (!chp)
		return ERR_PTR(-ENOMEM);

	chp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
	if (!chp->wr_waitp) {
		ret = -ENOMEM;
		goto err_free_chp;
	}
	c4iw_init_wr_wait(chp->wr_waitp);

	wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res);
	chp->destroy_skb = alloc_skb(wr_len, GFP_KERNEL);
	if (!chp->destroy_skb) {
		ret = -ENOMEM;
		goto err_free_wr_wait;
	}

	/* account for the status page. */
	entries++;

	/* IQ needs one extra entry to differentiate full vs empty. */
	entries++;

	/*
	 * entries must be multiple of 16 for HW.
	 */
	entries = roundup(entries, 16);

	/*
	 * Make actual HW queue 2x to avoid cdix_inc overflows.
	 */
	hwentries = min(entries * 2, rhp->rdev.hw_queue.t4_max_iq_size);

	/*
	 * Make HW queue at least 64 entries so GTS updates aren't too
	 * frequent.
	 */
	if (hwentries < 64)
		hwentries = 64;

	memsize = hwentries * ((ucontext && ucontext->is_32b_cqe) ?
			(sizeof(*chp->cq.queue) / 2) : sizeof(*chp->cq.queue));

	/*
	 * memsize must be a multiple of the page size if its a user cq.
	 */
	if (udata)
		memsize = roundup(memsize, PAGE_SIZE);

	chp->cq.size = hwentries;
	chp->cq.memsize = memsize;
	chp->cq.vector = vector;

	ret = create_cq(&rhp->rdev, &chp->cq,
			ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
			chp->wr_waitp);
	if (ret)
		goto err_free_skb;

	chp->rhp = rhp;
	chp->cq.size--;				/* status page */
	chp->ibcq.cqe = entries - 2;
	spin_lock_init(&chp->lock);
	spin_lock_init(&chp->comp_handler_lock);
	atomic_set(&chp->refcnt, 1);
	init_waitqueue_head(&chp->wait);
	ret = xa_insert_irq(&rhp->cqs, chp->cq.cqid, chp, GFP_KERNEL);
	if (ret)
		goto err_destroy_cq;

	if (ucontext) {
		ret = -ENOMEM;
		mm = kmalloc(sizeof *mm, GFP_KERNEL);
		if (!mm)
			goto err_remove_handle;
		mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
		if (!mm2)
			goto err_free_mm;

		memset(&uresp, 0, sizeof(uresp));
		uresp.qid_mask = rhp->rdev.cqmask;
		uresp.cqid = chp->cq.cqid;
		uresp.size = chp->cq.size;
		uresp.memsize = chp->cq.memsize;
		spin_lock(&ucontext->mmap_lock);
		uresp.key = ucontext->key;
		ucontext->key += PAGE_SIZE;
		uresp.gts_key = ucontext->key;
		ucontext->key += PAGE_SIZE;
		/* communicate to the userspace that
		 * kernel driver supports 64B CQE
		 */
		uresp.flags |= C4IW_64B_CQE;

		spin_unlock(&ucontext->mmap_lock);
		ret = ib_copy_to_udata(udata, &uresp,
				       ucontext->is_32b_cqe ?
				       sizeof(uresp) - sizeof(uresp.flags) :
				       sizeof(uresp));
		if (ret)
			goto err_free_mm2;

		mm->key = uresp.key;
		mm->addr = virt_to_phys(chp->cq.queue);
		mm->len = chp->cq.memsize;
		insert_mmap(ucontext, mm);

		mm2->key = uresp.gts_key;
		mm2->addr = chp->cq.bar2_pa;
		mm2->len = PAGE_SIZE;
		insert_mmap(ucontext, mm2);
	}
	pr_debug("cqid 0x%0x chp %p size %u memsize %zu, dma_addr 0x%0llx\n",
		 chp->cq.cqid, chp, chp->cq.size,
		 chp->cq.memsize, (unsigned long long)chp->cq.dma_addr);
	return &chp->ibcq;
err_free_mm2:
	kfree(mm2);
err_free_mm:
	kfree(mm);
err_remove_handle:
	xa_erase_irq(&rhp->cqs, chp->cq.cqid);
err_destroy_cq:
	destroy_cq(&chp->rhp->rdev, &chp->cq,
		   ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
		   chp->destroy_skb, chp->wr_waitp);
err_free_skb:
	kfree_skb(chp->destroy_skb);
err_free_wr_wait:
	c4iw_put_wr_wait(chp->wr_waitp);
err_free_chp:
	kfree(chp);
	return ERR_PTR(ret);
}