aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalph Campbell <ralph.campbell@qlogic.com>2007-09-07 19:54:01 -0400
committerRoland Dreier <rolandd@cisco.com>2007-10-09 23:52:23 -0400
commit6cff2faaf135b602c914710f3414630c3fc1ee83 (patch)
treea63266c7640b5739a6ab948194da0c7283229f96
parentd42b01b584b6f55f70c56f6a3dabc26f4982d30d (diff)
IB/ipath: Optimize completion queue entry insertion and polling
The code to add an entry to the completion queue stored the QPN which is needed for the user level verbs view of the completion queue entry but the kernel struct ib_wc contains a pointer to the QP instead of a QPN. When the kernel polled for a completion queue entry, the QPN was lookup up and the QP pointer recovered. This patch stores the CQE differently based on whether the CQ is a kernel CQ or a user CQ thus avoiding the QPN to QP lookup overhead. Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c94
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h6
2 files changed, 53 insertions, 47 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index a6f04d27ec57..645ed71fd797 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -76,22 +76,25 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
76 } 76 }
77 return; 77 return;
78 } 78 }
79 wc->queue[head].wr_id = entry->wr_id; 79 if (cq->ip) {
80 wc->queue[head].status = entry->status; 80 wc->uqueue[head].wr_id = entry->wr_id;
81 wc->queue[head].opcode = entry->opcode; 81 wc->uqueue[head].status = entry->status;
82 wc->queue[head].vendor_err = entry->vendor_err; 82 wc->uqueue[head].opcode = entry->opcode;
83 wc->queue[head].byte_len = entry->byte_len; 83 wc->uqueue[head].vendor_err = entry->vendor_err;
84 wc->queue[head].imm_data = (__u32 __force)entry->imm_data; 84 wc->uqueue[head].byte_len = entry->byte_len;
85 wc->queue[head].qp_num = entry->qp->qp_num; 85 wc->uqueue[head].imm_data = (__u32 __force)entry->imm_data;
86 wc->queue[head].src_qp = entry->src_qp; 86 wc->uqueue[head].qp_num = entry->qp->qp_num;
87 wc->queue[head].wc_flags = entry->wc_flags; 87 wc->uqueue[head].src_qp = entry->src_qp;
88 wc->queue[head].pkey_index = entry->pkey_index; 88 wc->uqueue[head].wc_flags = entry->wc_flags;
89 wc->queue[head].slid = entry->slid; 89 wc->uqueue[head].pkey_index = entry->pkey_index;
90 wc->queue[head].sl = entry->sl; 90 wc->uqueue[head].slid = entry->slid;
91 wc->queue[head].dlid_path_bits = entry->dlid_path_bits; 91 wc->uqueue[head].sl = entry->sl;
92 wc->queue[head].port_num = entry->port_num; 92 wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;
93 /* Make sure queue entry is written before the head index. */ 93 wc->uqueue[head].port_num = entry->port_num;
94 smp_wmb(); 94 /* Make sure entry is written before the head index. */
95 smp_wmb();
96 } else
97 wc->kqueue[head] = *entry;
95 wc->head = next; 98 wc->head = next;
96 99
97 if (cq->notify == IB_CQ_NEXT_COMP || 100 if (cq->notify == IB_CQ_NEXT_COMP ||
@@ -130,6 +133,12 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
130 int npolled; 133 int npolled;
131 u32 tail; 134 u32 tail;
132 135
136 /* The kernel can only poll a kernel completion queue */
137 if (cq->ip) {
138 npolled = -EINVAL;
139 goto bail;
140 }
141
133 spin_lock_irqsave(&cq->lock, flags); 142 spin_lock_irqsave(&cq->lock, flags);
134 143
135 wc = cq->queue; 144 wc = cq->queue;
@@ -137,31 +146,10 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
137 if (tail > (u32) cq->ibcq.cqe) 146 if (tail > (u32) cq->ibcq.cqe)
138 tail = (u32) cq->ibcq.cqe; 147 tail = (u32) cq->ibcq.cqe;
139 for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { 148 for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
140 struct ipath_qp *qp;
141
142 if (tail == wc->head) 149 if (tail == wc->head)
143 break; 150 break;
144 /* Make sure entry is read after head index is read. */ 151 /* The kernel doesn't need a RMB since it has the lock. */
145 smp_rmb(); 152 *entry = wc->kqueue[tail];
146 qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table,
147 wc->queue[tail].qp_num);
148 entry->qp = &qp->ibqp;
149 if (atomic_dec_and_test(&qp->refcount))
150 wake_up(&qp->wait);
151
152 entry->wr_id = wc->queue[tail].wr_id;
153 entry->status = wc->queue[tail].status;
154 entry->opcode = wc->queue[tail].opcode;
155 entry->vendor_err = wc->queue[tail].vendor_err;
156 entry->byte_len = wc->queue[tail].byte_len;
157 entry->imm_data = wc->queue[tail].imm_data;
158 entry->src_qp = wc->queue[tail].src_qp;
159 entry->wc_flags = wc->queue[tail].wc_flags;
160 entry->pkey_index = wc->queue[tail].pkey_index;
161 entry->slid = wc->queue[tail].slid;
162 entry->sl = wc->queue[tail].sl;
163 entry->dlid_path_bits = wc->queue[tail].dlid_path_bits;
164 entry->port_num = wc->queue[tail].port_num;
165 if (tail >= cq->ibcq.cqe) 153 if (tail >= cq->ibcq.cqe)
166 tail = 0; 154 tail = 0;
167 else 155 else
@@ -171,6 +159,7 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
171 159
172 spin_unlock_irqrestore(&cq->lock, flags); 160 spin_unlock_irqrestore(&cq->lock, flags);
173 161
162bail:
174 return npolled; 163 return npolled;
175} 164}
176 165
@@ -215,6 +204,7 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
215 struct ipath_cq *cq; 204 struct ipath_cq *cq;
216 struct ipath_cq_wc *wc; 205 struct ipath_cq_wc *wc;
217 struct ib_cq *ret; 206 struct ib_cq *ret;
207 u32 sz;
218 208
219 if (entries < 1 || entries > ib_ipath_max_cqes) { 209 if (entries < 1 || entries > ib_ipath_max_cqes) {
220 ret = ERR_PTR(-EINVAL); 210 ret = ERR_PTR(-EINVAL);
@@ -235,7 +225,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
235 * We need to use vmalloc() in order to support mmap and large 225 * We need to use vmalloc() in order to support mmap and large
236 * numbers of entries. 226 * numbers of entries.
237 */ 227 */
238 wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries); 228 sz = sizeof(*wc);
229 if (udata && udata->outlen >= sizeof(__u64))
230 sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
231 else
232 sz += sizeof(struct ib_wc) * (entries + 1);
233 wc = vmalloc_user(sz);
239 if (!wc) { 234 if (!wc) {
240 ret = ERR_PTR(-ENOMEM); 235 ret = ERR_PTR(-ENOMEM);
241 goto bail_cq; 236 goto bail_cq;
@@ -247,9 +242,8 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
247 */ 242 */
248 if (udata && udata->outlen >= sizeof(__u64)) { 243 if (udata && udata->outlen >= sizeof(__u64)) {
249 int err; 244 int err;
250 u32 s = sizeof *wc + sizeof(struct ib_wc) * entries;
251 245
252 cq->ip = ipath_create_mmap_info(dev, s, context, wc); 246 cq->ip = ipath_create_mmap_info(dev, sz, context, wc);
253 if (!cq->ip) { 247 if (!cq->ip) {
254 ret = ERR_PTR(-ENOMEM); 248 ret = ERR_PTR(-ENOMEM);
255 goto bail_wc; 249 goto bail_wc;
@@ -380,6 +374,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
380 struct ipath_cq_wc *wc; 374 struct ipath_cq_wc *wc;
381 u32 head, tail, n; 375 u32 head, tail, n;
382 int ret; 376 int ret;
377 u32 sz;
383 378
384 if (cqe < 1 || cqe > ib_ipath_max_cqes) { 379 if (cqe < 1 || cqe > ib_ipath_max_cqes) {
385 ret = -EINVAL; 380 ret = -EINVAL;
@@ -389,7 +384,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
389 /* 384 /*
390 * Need to use vmalloc() if we want to support large #s of entries. 385 * Need to use vmalloc() if we want to support large #s of entries.
391 */ 386 */
392 wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe); 387 sz = sizeof(*wc);
388 if (udata && udata->outlen >= sizeof(__u64))
389 sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
390 else
391 sz += sizeof(struct ib_wc) * (cqe + 1);
392 wc = vmalloc_user(sz);
393 if (!wc) { 393 if (!wc) {
394 ret = -ENOMEM; 394 ret = -ENOMEM;
395 goto bail; 395 goto bail;
@@ -430,7 +430,10 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
430 goto bail; 430 goto bail;
431 } 431 }
432 for (n = 0; tail != head; n++) { 432 for (n = 0; tail != head; n++) {
433 wc->queue[n] = old_wc->queue[tail]; 433 if (cq->ip)
434 wc->uqueue[n] = old_wc->uqueue[tail];
435 else
436 wc->kqueue[n] = old_wc->kqueue[tail];
434 if (tail == (u32) cq->ibcq.cqe) 437 if (tail == (u32) cq->ibcq.cqe)
435 tail = 0; 438 tail = 0;
436 else 439 else
@@ -447,9 +450,8 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
447 if (cq->ip) { 450 if (cq->ip) {
448 struct ipath_ibdev *dev = to_idev(ibcq->device); 451 struct ipath_ibdev *dev = to_idev(ibcq->device);
449 struct ipath_mmap_info *ip = cq->ip; 452 struct ipath_mmap_info *ip = cq->ip;
450 u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe;
451 453
452 ipath_update_mmap_info(dev, ip, s, wc); 454 ipath_update_mmap_info(dev, ip, sz, wc);
453 spin_lock_irq(&dev->pending_lock); 455 spin_lock_irq(&dev->pending_lock);
454 if (list_empty(&ip->pending_mmaps)) 456 if (list_empty(&ip->pending_mmaps))
455 list_add(&ip->pending_mmaps, &dev->pending_mmaps); 457 list_add(&ip->pending_mmaps, &dev->pending_mmaps);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index a1972295bffd..9be9bf91f4f0 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -191,7 +191,11 @@ struct ipath_mmap_info {
191struct ipath_cq_wc { 191struct ipath_cq_wc {
192 u32 head; /* index of next entry to fill */ 192 u32 head; /* index of next entry to fill */
193 u32 tail; /* index of next ib_poll_cq() entry */ 193 u32 tail; /* index of next ib_poll_cq() entry */
194 struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */ 194 union {
195 /* these are actually size ibcq.cqe + 1 */
196 struct ib_uverbs_wc uqueue[0];
197 struct ib_wc kqueue[0];
198 };
195}; 199};
196 200
197/* 201/*