Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 272353
b: refs/heads/master
c: af061a6
h: refs/heads/master
i:
  272351: 6c74da5
v: v3
  • Loading branch information
Mike Marciniszyn authored and Roland Dreier committed Oct 21, 2011
1 parent 83213ff commit 8895a29
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 42 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9e1c0e43257b6df1ef012dd37c3f0f93b1ee47af
refs/heads/master: af061a644a0e4d4778fe6cd2246479c1962e153b
3 changes: 3 additions & 0 deletions trunk/drivers/infiniband/hw/qib/qib.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ struct qib_ctxtdata {
/* ctxt rcvhdrq head offset */
u32 head;
u32 pkt_count;
/* lookaside fields */
struct qib_qp *lookaside_qp;
u32 lookaside_qpn;
/* QPs waiting for context processing */
struct list_head qp_wait_list;
};
Expand Down
9 changes: 9 additions & 0 deletions trunk/drivers/infiniband/hw/qib/qib_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,15 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts)
updegr = 0;
}
}
/*
* Notify qib_destroy_qp() if it is waiting
* for lookaside_qp to finish.
*/
if (rcd->lookaside_qp) {
if (atomic_dec_and_test(&rcd->lookaside_qp->refcount))
wake_up(&rcd->lookaside_qp->wait);
rcd->lookaside_qp = NULL;
}

rcd->head = l;
rcd->pkt_count += i;
Expand Down
77 changes: 48 additions & 29 deletions trunk/drivers/infiniband/hw/qib/qib_qp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#include <linux/err.h>
#include <linux/vmalloc.h>
#include <linux/jhash.h>

#include "qib.h"

Expand Down Expand Up @@ -204,29 +205,37 @@ static void free_qpn(struct qib_qpn_table *qpt, u32 qpn)
clear_bit(qpn & BITS_PER_PAGE_MASK, map->page);
}

static inline unsigned qpn_hash(struct qib_ibdev *dev, u32 qpn)
{
return jhash_1word(qpn, dev->qp_rnd) &
(dev->qp_table_size - 1);
}


/*
* Put the QP into the hash table.
* The hash table holds a reference to the QP.
*/
static void insert_qp(struct qib_ibdev *dev, struct qib_qp *qp)
{
struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
unsigned n = qp->ibqp.qp_num % dev->qp_table_size;
unsigned long flags;
unsigned n = qpn_hash(dev, qp->ibqp.qp_num);

spin_lock_irqsave(&dev->qpt_lock, flags);
atomic_inc(&qp->refcount);

if (qp->ibqp.qp_num == 0)
ibp->qp0 = qp;
rcu_assign_pointer(ibp->qp0, qp);
else if (qp->ibqp.qp_num == 1)
ibp->qp1 = qp;
rcu_assign_pointer(ibp->qp1, qp);
else {
qp->next = dev->qp_table[n];
dev->qp_table[n] = qp;
rcu_assign_pointer(dev->qp_table[n], qp);
}
atomic_inc(&qp->refcount);

spin_unlock_irqrestore(&dev->qpt_lock, flags);
synchronize_rcu();
}

/*
Expand All @@ -236,29 +245,32 @@ static void insert_qp(struct qib_ibdev *dev, struct qib_qp *qp)
static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
{
struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
struct qib_qp *q, **qpp;
unsigned n = qpn_hash(dev, qp->ibqp.qp_num);
unsigned long flags;

qpp = &dev->qp_table[qp->ibqp.qp_num % dev->qp_table_size];

spin_lock_irqsave(&dev->qpt_lock, flags);

if (ibp->qp0 == qp) {
ibp->qp0 = NULL;
atomic_dec(&qp->refcount);
rcu_assign_pointer(ibp->qp0, NULL);
} else if (ibp->qp1 == qp) {
ibp->qp1 = NULL;
atomic_dec(&qp->refcount);
} else
rcu_assign_pointer(ibp->qp1, NULL);
} else {
struct qib_qp *q, **qpp;

qpp = &dev->qp_table[n];
for (; (q = *qpp) != NULL; qpp = &q->next)
if (q == qp) {
*qpp = qp->next;
qp->next = NULL;
atomic_dec(&qp->refcount);
rcu_assign_pointer(*qpp, qp->next);
qp->next = NULL;
break;
}
}

spin_unlock_irqrestore(&dev->qpt_lock, flags);
synchronize_rcu();
}

/**
Expand All @@ -280,21 +292,24 @@ unsigned qib_free_all_qps(struct qib_devdata *dd)

if (!qib_mcast_tree_empty(ibp))
qp_inuse++;
if (ibp->qp0)
rcu_read_lock();
if (rcu_dereference(ibp->qp0))
qp_inuse++;
if (ibp->qp1)
if (rcu_dereference(ibp->qp1))
qp_inuse++;
rcu_read_unlock();
}

spin_lock_irqsave(&dev->qpt_lock, flags);
for (n = 0; n < dev->qp_table_size; n++) {
qp = dev->qp_table[n];
dev->qp_table[n] = NULL;
rcu_assign_pointer(dev->qp_table[n], NULL);

for (; qp; qp = qp->next)
qp_inuse++;
}
spin_unlock_irqrestore(&dev->qpt_lock, flags);
synchronize_rcu();

return qp_inuse;
}
Expand All @@ -309,25 +324,28 @@ unsigned qib_free_all_qps(struct qib_devdata *dd)
*/
struct qib_qp *qib_lookup_qpn(struct qib_ibport *ibp, u32 qpn)
{
struct qib_ibdev *dev = &ppd_from_ibp(ibp)->dd->verbs_dev;
unsigned long flags;
struct qib_qp *qp;
struct qib_qp *qp = NULL;

spin_lock_irqsave(&dev->qpt_lock, flags);
if (unlikely(qpn <= 1)) {
rcu_read_lock();
if (qpn == 0)
qp = rcu_dereference(ibp->qp0);
else
qp = rcu_dereference(ibp->qp1);
} else {
struct qib_ibdev *dev = &ppd_from_ibp(ibp)->dd->verbs_dev;
unsigned n = qpn_hash(dev, qpn);

if (qpn == 0)
qp = ibp->qp0;
else if (qpn == 1)
qp = ibp->qp1;
else
for (qp = dev->qp_table[qpn % dev->qp_table_size]; qp;
qp = qp->next)
rcu_read_lock();
for (qp = dev->qp_table[n]; rcu_dereference(qp); qp = qp->next)
if (qp->ibqp.qp_num == qpn)
break;
}
if (qp)
atomic_inc(&qp->refcount);
if (unlikely(!atomic_inc_not_zero(&qp->refcount)))
qp = NULL;

spin_unlock_irqrestore(&dev->qpt_lock, flags);
rcu_read_unlock();
return qp;
}

Expand Down Expand Up @@ -1015,6 +1033,7 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
ret = ERR_PTR(-ENOMEM);
goto bail_swq;
}
RCU_INIT_POINTER(qp->next, NULL);
if (init_attr->srq)
sz = 0;
else {
Expand Down
36 changes: 25 additions & 11 deletions trunk/drivers/infiniband/hw/qib/qib_verbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@
#include <linux/utsname.h>
#include <linux/rculist.h>
#include <linux/mm.h>
#include <linux/random.h>

#include "qib.h"
#include "qib_common.h"

static unsigned int ib_qib_qp_table_size = 251;
static unsigned int ib_qib_qp_table_size = 256;
module_param_named(qp_table_size, ib_qib_qp_table_size, uint, S_IRUGO);
MODULE_PARM_DESC(qp_table_size, "QP table size");

Expand Down Expand Up @@ -659,17 +660,25 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
if (atomic_dec_return(&mcast->refcount) <= 1)
wake_up(&mcast->wait);
} else {
qp = qib_lookup_qpn(ibp, qp_num);
if (!qp)
goto drop;
if (rcd->lookaside_qp) {
if (rcd->lookaside_qpn != qp_num) {
if (atomic_dec_and_test(
&rcd->lookaside_qp->refcount))
wake_up(
&rcd->lookaside_qp->wait);
rcd->lookaside_qp = NULL;
}
}
if (!rcd->lookaside_qp) {
qp = qib_lookup_qpn(ibp, qp_num);
if (!qp)
goto drop;
rcd->lookaside_qp = qp;
rcd->lookaside_qpn = qp_num;
} else
qp = rcd->lookaside_qp;
ibp->n_unicast_rcv++;
qib_qp_rcv(rcd, hdr, lnh == QIB_LRH_GRH, data, tlen, qp);
/*
* Notify qib_destroy_qp() if it is waiting
* for us to finish.
*/
if (atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
}
return;

Expand Down Expand Up @@ -1974,6 +1983,8 @@ static void init_ibport(struct qib_pportdata *ppd)
ibp->z_excessive_buffer_overrun_errors =
cntrs.excessive_buffer_overrun_errors;
ibp->z_vl15_dropped = cntrs.vl15_dropped;
RCU_INIT_POINTER(ibp->qp0, NULL);
RCU_INIT_POINTER(ibp->qp1, NULL);
}

/**
Expand All @@ -1990,12 +2001,15 @@ int qib_register_ib_device(struct qib_devdata *dd)
int ret;

dev->qp_table_size = ib_qib_qp_table_size;
dev->qp_table = kzalloc(dev->qp_table_size * sizeof *dev->qp_table,
get_random_bytes(&dev->qp_rnd, sizeof(dev->qp_rnd));
dev->qp_table = kmalloc(dev->qp_table_size * sizeof *dev->qp_table,
GFP_KERNEL);
if (!dev->qp_table) {
ret = -ENOMEM;
goto err_qpt;
}
for (i = 0; i < dev->qp_table_size; i++)
RCU_INIT_POINTER(dev->qp_table[i], NULL);

for (i = 0; i < dd->num_pports; i++)
init_ibport(ppd + i);
Expand Down
3 changes: 2 additions & 1 deletion trunk/drivers/infiniband/hw/qib/qib_verbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,8 @@ struct qib_ibdev {
dma_addr_t pio_hdrs_phys;
/* list of QPs waiting for RNR timer */
spinlock_t pending_lock; /* protect wait lists, PMA counters, etc. */
unsigned qp_table_size; /* size of the hash table */
u32 qp_table_size; /* size of the hash table */
u32 qp_rnd; /* random bytes for hash */
spinlock_t qpt_lock;

u32 n_piowait;
Expand Down

0 comments on commit 8895a29

Please sign in to comment.