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

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

Signed-off-by: default avatarRobert Walsh <robert.walsh@qlogic.com>
Signed-off-by: default avatarBryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 53c1d2c9
...@@ -81,33 +81,61 @@ static u32 credit_table[31] = { ...@@ -81,33 +81,61 @@ static u32 credit_table[31] = {
32768 /* 1E */ 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; static void get_map_page(struct ipath_qp_table *qpt, struct qpn_map *map)
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)) {
unsigned long page = get_zeroed_page(GFP_KERNEL); unsigned long page = get_zeroed_page(GFP_KERNEL);
unsigned long flags; unsigned long flags;
/* /*
* Free the page if someone raced with us * Free the page if someone raced with us installing it.
* installing it:
*/ */
spin_lock_irqsave(&qpt->lock, flags); spin_lock_irqsave(&qpt->lock, flags);
if (map->page) if (map->page)
free_page(page); free_page(page);
else else
map->page = (void *)page; map->page = (void *)page;
spin_unlock_irqrestore(&qpt->lock, flags); 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)) if (unlikely(!map->page))
break; break;
} }
...@@ -151,7 +179,7 @@ static u32 alloc_qpn(struct ipath_qp_table *qpt) ...@@ -151,7 +179,7 @@ static u32 alloc_qpn(struct ipath_qp_table *qpt)
qpn = mk_qpn(qpt, map, offset); qpn = mk_qpn(qpt, map, offset);
} }
ret = 0; ret = -ENOMEM;
bail: bail:
return ret; return ret;
...@@ -180,29 +208,19 @@ static int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp, ...@@ -180,29 +208,19 @@ static int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp,
enum ib_qp_type type) enum ib_qp_type type)
{ {
unsigned long flags; unsigned long flags;
u32 qpn;
int ret; int ret;
if (type == IB_QPT_SMI) ret = alloc_qpn(qpt, type);
qpn = 0; if (ret < 0)
else if (type == IB_QPT_GSI)
qpn = 1;
else {
/* Allocate the next available QPN */
qpn = alloc_qpn(qpt);
if (qpn == 0) {
ret = -ENOMEM;
goto bail; goto bail;
} qp->ibqp.qp_num = ret;
}
qp->ibqp.qp_num = qpn;
/* Add the QP to the hash table. */ /* Add the QP to the hash table. */
spin_lock_irqsave(&qpt->lock, flags); spin_lock_irqsave(&qpt->lock, flags);
qpn %= qpt->max; ret %= qpt->max;
qp->next = qpt->table[qpn]; qp->next = qpt->table[ret];
qpt->table[qpn] = qp; qpt->table[ret] = qp;
atomic_inc(&qp->refcount); atomic_inc(&qp->refcount);
spin_unlock_irqrestore(&qpt->lock, flags); spin_unlock_irqrestore(&qpt->lock, flags);
...@@ -245,8 +263,6 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp) ...@@ -245,8 +263,6 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp)
if (!fnd) if (!fnd)
return; 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); free_qpn(qpt, qp->ibqp.qp_num);
wait_event(qp->wait, !atomic_read(&qp->refcount)); wait_event(qp->wait, !atomic_read(&qp->refcount));
...@@ -270,7 +286,6 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt) ...@@ -270,7 +286,6 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt)
while (qp) { while (qp) {
nqp = qp->next; nqp = qp->next;
if (qp->ibqp.qp_num > 1)
free_qpn(qpt, qp->ibqp.qp_num); free_qpn(qpt, qp->ibqp.qp_num);
if (!atomic_dec_and_test(&qp->refcount) || if (!atomic_dec_and_test(&qp->refcount) ||
!ipath_destroy_qp(&qp->ibqp)) !ipath_destroy_qp(&qp->ibqp))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment