diff options
author | Ralph Campbell <ralph.campbell@qlogic.com> | 2008-05-13 14:41:29 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-05-13 14:41:29 -0400 |
commit | e509be898d8937634437caa474b57ac12795e5bc (patch) | |
tree | f99b0e3965ee0eaf89acccdba382689719881a29 /drivers/infiniband/hw/ipath/ipath_ud.c | |
parent | 53dc1ca194c062aa9771e194047f27ec1ca592df (diff) |
IB/ipath: Fix many locking issues when switching to error state
The send DMA hardware queue voided a number of prior assumptions about
when a send is complete which led to completions being generated out of
order. There were also a number of locking issues when switching the QP
to the error or reset states, and we implement the IB_QPS_SQD state.
Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_ud.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_ud.c | 66 |
1 files changed, 48 insertions, 18 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 8b6a261c89e3..77ca8ca74e78 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c | |||
@@ -65,9 +65,9 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) | |||
65 | u32 length; | 65 | u32 length; |
66 | 66 | ||
67 | qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn); | 67 | qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn); |
68 | if (!qp) { | 68 | if (!qp || !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) { |
69 | dev->n_pkt_drops++; | 69 | dev->n_pkt_drops++; |
70 | goto send_comp; | 70 | goto done; |
71 | } | 71 | } |
72 | 72 | ||
73 | rsge.sg_list = NULL; | 73 | rsge.sg_list = NULL; |
@@ -91,14 +91,12 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) | |||
91 | * present on the wire. | 91 | * present on the wire. |
92 | */ | 92 | */ |
93 | length = swqe->length; | 93 | length = swqe->length; |
94 | memset(&wc, 0, sizeof wc); | ||
94 | wc.byte_len = length + sizeof(struct ib_grh); | 95 | wc.byte_len = length + sizeof(struct ib_grh); |
95 | 96 | ||
96 | if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) { | 97 | if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) { |
97 | wc.wc_flags = IB_WC_WITH_IMM; | 98 | wc.wc_flags = IB_WC_WITH_IMM; |
98 | wc.imm_data = swqe->wr.ex.imm_data; | 99 | wc.imm_data = swqe->wr.ex.imm_data; |
99 | } else { | ||
100 | wc.wc_flags = 0; | ||
101 | wc.imm_data = 0; | ||
102 | } | 100 | } |
103 | 101 | ||
104 | /* | 102 | /* |
@@ -229,7 +227,6 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) | |||
229 | } | 227 | } |
230 | wc.status = IB_WC_SUCCESS; | 228 | wc.status = IB_WC_SUCCESS; |
231 | wc.opcode = IB_WC_RECV; | 229 | wc.opcode = IB_WC_RECV; |
232 | wc.vendor_err = 0; | ||
233 | wc.qp = &qp->ibqp; | 230 | wc.qp = &qp->ibqp; |
234 | wc.src_qp = sqp->ibqp.qp_num; | 231 | wc.src_qp = sqp->ibqp.qp_num; |
235 | /* XXX do we know which pkey matched? Only needed for GSI. */ | 232 | /* XXX do we know which pkey matched? Only needed for GSI. */ |
@@ -248,8 +245,7 @@ drop: | |||
248 | kfree(rsge.sg_list); | 245 | kfree(rsge.sg_list); |
249 | if (atomic_dec_and_test(&qp->refcount)) | 246 | if (atomic_dec_and_test(&qp->refcount)) |
250 | wake_up(&qp->wait); | 247 | wake_up(&qp->wait); |
251 | send_comp: | 248 | done:; |
252 | ipath_send_complete(sqp, swqe, IB_WC_SUCCESS); | ||
253 | } | 249 | } |
254 | 250 | ||
255 | /** | 251 | /** |
@@ -264,6 +260,7 @@ int ipath_make_ud_req(struct ipath_qp *qp) | |||
264 | struct ipath_other_headers *ohdr; | 260 | struct ipath_other_headers *ohdr; |
265 | struct ib_ah_attr *ah_attr; | 261 | struct ib_ah_attr *ah_attr; |
266 | struct ipath_swqe *wqe; | 262 | struct ipath_swqe *wqe; |
263 | unsigned long flags; | ||
267 | u32 nwords; | 264 | u32 nwords; |
268 | u32 extra_bytes; | 265 | u32 extra_bytes; |
269 | u32 bth0; | 266 | u32 bth0; |
@@ -271,13 +268,30 @@ int ipath_make_ud_req(struct ipath_qp *qp) | |||
271 | u16 lid; | 268 | u16 lid; |
272 | int ret = 0; | 269 | int ret = 0; |
273 | 270 | ||
274 | if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))) | 271 | spin_lock_irqsave(&qp->s_lock, flags); |
275 | goto bail; | 272 | |
273 | if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_NEXT_SEND_OK)) { | ||
274 | if (!(ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND)) | ||
275 | goto bail; | ||
276 | /* We are in the error state, flush the work request. */ | ||
277 | if (qp->s_last == qp->s_head) | ||
278 | goto bail; | ||
279 | /* If DMAs are in progress, we can't flush immediately. */ | ||
280 | if (atomic_read(&qp->s_dma_busy)) { | ||
281 | qp->s_flags |= IPATH_S_WAIT_DMA; | ||
282 | goto bail; | ||
283 | } | ||
284 | wqe = get_swqe_ptr(qp, qp->s_last); | ||
285 | ipath_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); | ||
286 | goto done; | ||
287 | } | ||
276 | 288 | ||
277 | if (qp->s_cur == qp->s_head) | 289 | if (qp->s_cur == qp->s_head) |
278 | goto bail; | 290 | goto bail; |
279 | 291 | ||
280 | wqe = get_swqe_ptr(qp, qp->s_cur); | 292 | wqe = get_swqe_ptr(qp, qp->s_cur); |
293 | if (++qp->s_cur >= qp->s_size) | ||
294 | qp->s_cur = 0; | ||
281 | 295 | ||
282 | /* Construct the header. */ | 296 | /* Construct the header. */ |
283 | ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr; | 297 | ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr; |
@@ -288,10 +302,23 @@ int ipath_make_ud_req(struct ipath_qp *qp) | |||
288 | dev->n_unicast_xmit++; | 302 | dev->n_unicast_xmit++; |
289 | } else { | 303 | } else { |
290 | dev->n_unicast_xmit++; | 304 | dev->n_unicast_xmit++; |
291 | lid = ah_attr->dlid & | 305 | lid = ah_attr->dlid & ~((1 << dev->dd->ipath_lmc) - 1); |
292 | ~((1 << dev->dd->ipath_lmc) - 1); | ||
293 | if (unlikely(lid == dev->dd->ipath_lid)) { | 306 | if (unlikely(lid == dev->dd->ipath_lid)) { |
307 | /* | ||
308 | * If DMAs are in progress, we can't generate | ||
309 | * a completion for the loopback packet since | ||
310 | * it would be out of order. | ||
311 | * XXX Instead of waiting, we could queue a | ||
312 | * zero length descriptor so we get a callback. | ||
313 | */ | ||
314 | if (atomic_read(&qp->s_dma_busy)) { | ||
315 | qp->s_flags |= IPATH_S_WAIT_DMA; | ||
316 | goto bail; | ||
317 | } | ||
318 | spin_unlock_irqrestore(&qp->s_lock, flags); | ||
294 | ipath_ud_loopback(qp, wqe); | 319 | ipath_ud_loopback(qp, wqe); |
320 | spin_lock_irqsave(&qp->s_lock, flags); | ||
321 | ipath_send_complete(qp, wqe, IB_WC_SUCCESS); | ||
295 | goto done; | 322 | goto done; |
296 | } | 323 | } |
297 | } | 324 | } |
@@ -368,11 +395,13 @@ int ipath_make_ud_req(struct ipath_qp *qp) | |||
368 | ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num); | 395 | ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num); |
369 | 396 | ||
370 | done: | 397 | done: |
371 | if (++qp->s_cur >= qp->s_size) | ||
372 | qp->s_cur = 0; | ||
373 | ret = 1; | 398 | ret = 1; |
399 | goto unlock; | ||
374 | 400 | ||
375 | bail: | 401 | bail: |
402 | qp->s_flags &= ~IPATH_S_BUSY; | ||
403 | unlock: | ||
404 | spin_unlock_irqrestore(&qp->s_lock, flags); | ||
376 | return ret; | 405 | return ret; |
377 | } | 406 | } |
378 | 407 | ||
@@ -506,8 +535,8 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
506 | /* | 535 | /* |
507 | * Get the next work request entry to find where to put the data. | 536 | * Get the next work request entry to find where to put the data. |
508 | */ | 537 | */ |
509 | if (qp->r_reuse_sge) | 538 | if (qp->r_flags & IPATH_R_REUSE_SGE) |
510 | qp->r_reuse_sge = 0; | 539 | qp->r_flags &= ~IPATH_R_REUSE_SGE; |
511 | else if (!ipath_get_rwqe(qp, 0)) { | 540 | else if (!ipath_get_rwqe(qp, 0)) { |
512 | /* | 541 | /* |
513 | * Count VL15 packets dropped due to no receive buffer. | 542 | * Count VL15 packets dropped due to no receive buffer. |
@@ -523,7 +552,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
523 | } | 552 | } |
524 | /* Silently drop packets which are too big. */ | 553 | /* Silently drop packets which are too big. */ |
525 | if (wc.byte_len > qp->r_len) { | 554 | if (wc.byte_len > qp->r_len) { |
526 | qp->r_reuse_sge = 1; | 555 | qp->r_flags |= IPATH_R_REUSE_SGE; |
527 | dev->n_pkt_drops++; | 556 | dev->n_pkt_drops++; |
528 | goto bail; | 557 | goto bail; |
529 | } | 558 | } |
@@ -535,7 +564,8 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
535 | ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh)); | 564 | ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh)); |
536 | ipath_copy_sge(&qp->r_sge, data, | 565 | ipath_copy_sge(&qp->r_sge, data, |
537 | wc.byte_len - sizeof(struct ib_grh)); | 566 | wc.byte_len - sizeof(struct ib_grh)); |
538 | qp->r_wrid_valid = 0; | 567 | if (!test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags)) |
568 | goto bail; | ||
539 | wc.wr_id = qp->r_wr_id; | 569 | wc.wr_id = qp->r_wr_id; |
540 | wc.status = IB_WC_SUCCESS; | 570 | wc.status = IB_WC_SUCCESS; |
541 | wc.opcode = IB_WC_RECV; | 571 | wc.opcode = IB_WC_RECV; |