IB/qib: Use RCU for qpn lookup
The heavy weight spinlock in qib_lookup_qpn() is replaced with RCU. The hash list itself is now accessed via jhash functions instead of mod. The changes should benefit multiple receive contexts in different processors by not contending for the lock just to read the hash structures. The patch also adds a lookaside_qp (pointer) and a lookaside_qpn in the context. The interrupt handler will test the current packet's qpn against lookaside_qpn if the lookaside_qp pointer is non-NULL. The pointer is NULL'ed when the interrupt handler exits. Signed-off-by: Mike Marciniszyn <mike.marciniszyn@qlogic.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
This commit is contained in:

committed by
Roland Dreier

parent
9e1c0e4325
commit
af061a644a
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
|
Reference in New Issue
Block a user