Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 662af581 authored by Bryan O'Sullivan's avatar Bryan O'Sullivan Committed by Roland Dreier
Browse files

IB/ipath: Don't allow QPs 0 and 1 to be opened multiple times

parent 53c1d2c9
Loading
Loading
Loading
Loading
+53 −38
Original line number Diff line number Diff line
@@ -81,33 +81,61 @@ static u32 credit_table[31] = {
	32768			/* 1E */
};

static u32 alloc_qpn(struct ipath_qp_table *qpt)
{
	u32 i, offset, max_scan, qpn;
	struct qpn_map *map;
	u32 ret;

	qpn = qpt->last + 1;
	if (qpn >= QPN_MAX)
		qpn = 2;
	offset = qpn & BITS_PER_PAGE_MASK;
	map = &qpt->map[qpn / BITS_PER_PAGE];
	max_scan = qpt->nmaps - !offset;
	for (i = 0;;) {
		if (unlikely(!map->page)) {
static void get_map_page(struct ipath_qp_table *qpt, struct qpn_map *map)
{
	unsigned long page = get_zeroed_page(GFP_KERNEL);
	unsigned long flags;

	/*
			 * Free the page if someone raced with us
			 * installing it:
	 * Free the page if someone raced with us installing it.
	 */

	spin_lock_irqsave(&qpt->lock, flags);
	if (map->page)
		free_page(page);
	else
		map->page = (void *)page;
	spin_unlock_irqrestore(&qpt->lock, flags);
}


static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type)
{
	u32 i, offset, max_scan, qpn;
	struct qpn_map *map;
	u32 ret = -1;

	if (type == IB_QPT_SMI)
		ret = 0;
	else if (type == IB_QPT_GSI)
		ret = 1;

	if (ret != -1) {
		map = &qpt->map[0];
		if (unlikely(!map->page)) {
			get_map_page(qpt, map);
			if (unlikely(!map->page)) {
				ret = -ENOMEM;
				goto bail;
			}
		}
		if (!test_and_set_bit(ret, map->page))
			atomic_dec(&map->n_free);
		else
			ret = -EBUSY;
		goto bail;
	}

	qpn = qpt->last + 1;
	if (qpn >= QPN_MAX)
		qpn = 2;
	offset = qpn & BITS_PER_PAGE_MASK;
	map = &qpt->map[qpn / BITS_PER_PAGE];
	max_scan = qpt->nmaps - !offset;
	for (i = 0;;) {
		if (unlikely(!map->page)) {
			get_map_page(qpt, map);
			if (unlikely(!map->page))
				break;
		}
@@ -151,7 +179,7 @@ static u32 alloc_qpn(struct ipath_qp_table *qpt)
		qpn = mk_qpn(qpt, map, offset);
	}

	ret = 0;
	ret = -ENOMEM;

bail:
	return ret;
@@ -180,29 +208,19 @@ static int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp,
			   enum ib_qp_type type)
{
	unsigned long flags;
	u32 qpn;
	int ret;

	if (type == IB_QPT_SMI)
		qpn = 0;
	else if (type == IB_QPT_GSI)
		qpn = 1;
	else {
		/* Allocate the next available QPN */
		qpn = alloc_qpn(qpt);
		if (qpn == 0) {
			ret = -ENOMEM;
	ret = alloc_qpn(qpt, type);
	if (ret < 0)
		goto bail;
		}
	}
	qp->ibqp.qp_num = qpn;
	qp->ibqp.qp_num = ret;

	/* Add the QP to the hash table. */
	spin_lock_irqsave(&qpt->lock, flags);

	qpn %= qpt->max;
	qp->next = qpt->table[qpn];
	qpt->table[qpn] = qp;
	ret %= qpt->max;
	qp->next = qpt->table[ret];
	qpt->table[ret] = qp;
	atomic_inc(&qp->refcount);

	spin_unlock_irqrestore(&qpt->lock, flags);
@@ -245,8 +263,6 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp)
	if (!fnd)
		return;

	/* If QPN is not reserved, mark QPN free in the bitmap. */
	if (qp->ibqp.qp_num > 1)
	free_qpn(qpt, qp->ibqp.qp_num);

	wait_event(qp->wait, !atomic_read(&qp->refcount));
@@ -270,7 +286,6 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt)

		while (qp) {
			nqp = qp->next;
			if (qp->ibqp.qp_num > 1)
			free_qpn(qpt, qp->ibqp.qp_num);
			if (!atomic_dec_and_test(&qp->refcount) ||
			    !ipath_destroy_qp(&qp->ibqp))