.. | .. |
---|
79 | 79 | } |
---|
80 | 80 | } |
---|
81 | 81 | |
---|
| 82 | +static void qedr_iw_free_qp(struct kref *ref) |
---|
| 83 | +{ |
---|
| 84 | + struct qedr_qp *qp = container_of(ref, struct qedr_qp, refcnt); |
---|
| 85 | + |
---|
| 86 | + kfree(qp); |
---|
| 87 | +} |
---|
| 88 | + |
---|
| 89 | +static void |
---|
| 90 | +qedr_iw_free_ep(struct kref *ref) |
---|
| 91 | +{ |
---|
| 92 | + struct qedr_iw_ep *ep = container_of(ref, struct qedr_iw_ep, refcnt); |
---|
| 93 | + |
---|
| 94 | + if (ep->qp) |
---|
| 95 | + kref_put(&ep->qp->refcnt, qedr_iw_free_qp); |
---|
| 96 | + |
---|
| 97 | + if (ep->cm_id) |
---|
| 98 | + ep->cm_id->rem_ref(ep->cm_id); |
---|
| 99 | + |
---|
| 100 | + kfree(ep); |
---|
| 101 | +} |
---|
| 102 | + |
---|
82 | 103 | static void |
---|
83 | 104 | qedr_iw_mpa_request(void *context, struct qed_iwarp_cm_event_params *params) |
---|
84 | 105 | { |
---|
.. | .. |
---|
93 | 114 | |
---|
94 | 115 | ep->dev = dev; |
---|
95 | 116 | ep->qed_context = params->ep_context; |
---|
| 117 | + kref_init(&ep->refcnt); |
---|
96 | 118 | |
---|
97 | 119 | memset(&event, 0, sizeof(event)); |
---|
98 | 120 | event.event = IW_CM_EVENT_CONNECT_REQUEST; |
---|
.. | .. |
---|
150 | 172 | { |
---|
151 | 173 | struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; |
---|
152 | 174 | |
---|
153 | | - if (ep->cm_id) { |
---|
| 175 | + if (ep->cm_id) |
---|
154 | 176 | qedr_iw_issue_event(context, params, IW_CM_EVENT_CLOSE); |
---|
155 | 177 | |
---|
156 | | - ep->cm_id->rem_ref(ep->cm_id); |
---|
157 | | - ep->cm_id = NULL; |
---|
158 | | - } |
---|
| 178 | + kref_put(&ep->refcnt, qedr_iw_free_ep); |
---|
159 | 179 | } |
---|
160 | 180 | |
---|
161 | 181 | static void |
---|
.. | .. |
---|
195 | 215 | struct qedr_qp *qp = ep->qp; |
---|
196 | 216 | struct iw_cm_event event; |
---|
197 | 217 | |
---|
198 | | - if (qp->destroyed) { |
---|
199 | | - kfree(dwork); |
---|
200 | | - qedr_iw_qp_rem_ref(&qp->ibqp); |
---|
201 | | - return; |
---|
202 | | - } |
---|
| 218 | + /* The qp won't be released until we release the ep. |
---|
| 219 | + * the ep's refcnt was increased before calling this |
---|
| 220 | + * function, therefore it is safe to access qp |
---|
| 221 | + */ |
---|
| 222 | + if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT, |
---|
| 223 | + &qp->iwarp_cm_flags)) |
---|
| 224 | + goto out; |
---|
203 | 225 | |
---|
204 | 226 | memset(&event, 0, sizeof(event)); |
---|
205 | 227 | event.status = dwork->status; |
---|
.. | .. |
---|
213 | 235 | else |
---|
214 | 236 | qp_params.new_state = QED_ROCE_QP_STATE_SQD; |
---|
215 | 237 | |
---|
216 | | - kfree(dwork); |
---|
217 | 238 | |
---|
218 | 239 | if (ep->cm_id) |
---|
219 | 240 | ep->cm_id->event_handler(ep->cm_id, &event); |
---|
.. | .. |
---|
223 | 244 | |
---|
224 | 245 | dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params); |
---|
225 | 246 | |
---|
226 | | - qedr_iw_qp_rem_ref(&qp->ibqp); |
---|
| 247 | + complete(&ep->qp->iwarp_cm_comp); |
---|
| 248 | +out: |
---|
| 249 | + kfree(dwork); |
---|
| 250 | + kref_put(&ep->refcnt, qedr_iw_free_ep); |
---|
227 | 251 | } |
---|
228 | 252 | |
---|
229 | 253 | static void |
---|
.. | .. |
---|
233 | 257 | struct qedr_discon_work *work; |
---|
234 | 258 | struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; |
---|
235 | 259 | struct qedr_dev *dev = ep->dev; |
---|
236 | | - struct qedr_qp *qp = ep->qp; |
---|
237 | 260 | |
---|
238 | 261 | work = kzalloc(sizeof(*work), GFP_ATOMIC); |
---|
239 | 262 | if (!work) |
---|
240 | 263 | return; |
---|
241 | 264 | |
---|
242 | | - qedr_iw_qp_add_ref(&qp->ibqp); |
---|
| 265 | + /* We can't get a close event before disconnect, but since |
---|
| 266 | + * we're scheduling a work queue we need to make sure close |
---|
| 267 | + * won't delete the ep, so we increase the refcnt |
---|
| 268 | + */ |
---|
| 269 | + kref_get(&ep->refcnt); |
---|
| 270 | + |
---|
243 | 271 | work->ep = ep; |
---|
244 | 272 | work->event = params->event; |
---|
245 | 273 | work->status = params->status; |
---|
.. | .. |
---|
261 | 289 | if ((params->status == -ECONNREFUSED) && (!ep->qp)) { |
---|
262 | 290 | DP_DEBUG(dev, QEDR_MSG_IWARP, |
---|
263 | 291 | "PASSIVE connection refused releasing ep...\n"); |
---|
264 | | - kfree(ep); |
---|
| 292 | + kref_put(&ep->refcnt, qedr_iw_free_ep); |
---|
265 | 293 | return; |
---|
266 | 294 | } |
---|
267 | 295 | |
---|
| 296 | + complete(&ep->qp->iwarp_cm_comp); |
---|
268 | 297 | qedr_iw_issue_event(context, params, IW_CM_EVENT_ESTABLISHED); |
---|
269 | 298 | |
---|
270 | 299 | if (params->status < 0) |
---|
271 | 300 | qedr_iw_close_event(context, params); |
---|
| 301 | +} |
---|
| 302 | + |
---|
| 303 | +static void |
---|
| 304 | +qedr_iw_active_complete(void *context, |
---|
| 305 | + struct qed_iwarp_cm_event_params *params) |
---|
| 306 | +{ |
---|
| 307 | + struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; |
---|
| 308 | + |
---|
| 309 | + complete(&ep->qp->iwarp_cm_comp); |
---|
| 310 | + qedr_iw_issue_event(context, params, IW_CM_EVENT_CONNECT_REPLY); |
---|
| 311 | + |
---|
| 312 | + if (params->status < 0) |
---|
| 313 | + kref_put(&ep->refcnt, qedr_iw_free_ep); |
---|
272 | 314 | } |
---|
273 | 315 | |
---|
274 | 316 | static int |
---|
.. | .. |
---|
297 | 339 | qedr_iw_mpa_reply(context, params); |
---|
298 | 340 | break; |
---|
299 | 341 | case QED_IWARP_EVENT_PASSIVE_COMPLETE: |
---|
300 | | - ep->during_connect = 0; |
---|
301 | 342 | qedr_iw_passive_complete(context, params); |
---|
302 | 343 | break; |
---|
303 | | - |
---|
304 | 344 | case QED_IWARP_EVENT_ACTIVE_COMPLETE: |
---|
305 | | - ep->during_connect = 0; |
---|
306 | | - qedr_iw_issue_event(context, |
---|
307 | | - params, |
---|
308 | | - IW_CM_EVENT_CONNECT_REPLY); |
---|
309 | | - if (params->status < 0) { |
---|
310 | | - struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; |
---|
311 | | - |
---|
312 | | - ep->cm_id->rem_ref(ep->cm_id); |
---|
313 | | - ep->cm_id = NULL; |
---|
314 | | - } |
---|
| 345 | + qedr_iw_active_complete(context, params); |
---|
315 | 346 | break; |
---|
316 | 347 | case QED_IWARP_EVENT_DISCONNECT: |
---|
317 | 348 | qedr_iw_disconnect_event(context, params); |
---|
318 | 349 | break; |
---|
319 | 350 | case QED_IWARP_EVENT_CLOSE: |
---|
320 | | - ep->during_connect = 0; |
---|
321 | 351 | qedr_iw_close_event(context, params); |
---|
322 | 352 | break; |
---|
323 | 353 | case QED_IWARP_EVENT_RQ_EMPTY: |
---|
.. | .. |
---|
358 | 388 | default: |
---|
359 | 389 | DP_NOTICE(dev, "Unknown event received %d\n", params->event); |
---|
360 | 390 | break; |
---|
361 | | - }; |
---|
| 391 | + } |
---|
362 | 392 | return 0; |
---|
363 | 393 | } |
---|
364 | 394 | |
---|
.. | .. |
---|
485 | 515 | return rc; |
---|
486 | 516 | } |
---|
487 | 517 | |
---|
| 518 | +static struct qedr_qp *qedr_iw_load_qp(struct qedr_dev *dev, u32 qpn) |
---|
| 519 | +{ |
---|
| 520 | + struct qedr_qp *qp; |
---|
| 521 | + |
---|
| 522 | + xa_lock(&dev->qps); |
---|
| 523 | + qp = xa_load(&dev->qps, qpn); |
---|
| 524 | + if (qp) |
---|
| 525 | + kref_get(&qp->refcnt); |
---|
| 526 | + xa_unlock(&dev->qps); |
---|
| 527 | + |
---|
| 528 | + return qp; |
---|
| 529 | +} |
---|
| 530 | + |
---|
488 | 531 | int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) |
---|
489 | 532 | { |
---|
490 | 533 | struct qedr_dev *dev = get_qedr_dev(cm_id->device); |
---|
.. | .. |
---|
499 | 542 | struct qedr_qp *qp; |
---|
500 | 543 | int rc = 0; |
---|
501 | 544 | int i; |
---|
502 | | - |
---|
503 | | - qp = idr_find(&dev->qpidr.idr, conn_param->qpn); |
---|
504 | | - if (unlikely(!qp)) |
---|
505 | | - return -EINVAL; |
---|
506 | 545 | |
---|
507 | 546 | laddr = (struct sockaddr_in *)&cm_id->m_local_addr; |
---|
508 | 547 | raddr = (struct sockaddr_in *)&cm_id->m_remote_addr; |
---|
.. | .. |
---|
525 | 564 | return -ENOMEM; |
---|
526 | 565 | |
---|
527 | 566 | ep->dev = dev; |
---|
| 567 | + kref_init(&ep->refcnt); |
---|
| 568 | + |
---|
| 569 | + qp = qedr_iw_load_qp(dev, conn_param->qpn); |
---|
| 570 | + if (!qp) { |
---|
| 571 | + rc = -EINVAL; |
---|
| 572 | + goto err; |
---|
| 573 | + } |
---|
| 574 | + |
---|
528 | 575 | ep->qp = qp; |
---|
529 | | - qp->ep = ep; |
---|
530 | 576 | cm_id->add_ref(cm_id); |
---|
531 | 577 | ep->cm_id = cm_id; |
---|
532 | 578 | |
---|
.. | .. |
---|
589 | 635 | in_params.qp = qp->qed_qp; |
---|
590 | 636 | memcpy(in_params.local_mac_addr, dev->ndev->dev_addr, ETH_ALEN); |
---|
591 | 637 | |
---|
592 | | - ep->during_connect = 1; |
---|
| 638 | + if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT, |
---|
| 639 | + &qp->iwarp_cm_flags)) { |
---|
| 640 | + rc = -ENODEV; |
---|
| 641 | + goto err; /* QP already being destroyed */ |
---|
| 642 | + } |
---|
| 643 | + |
---|
593 | 644 | rc = dev->ops->iwarp_connect(dev->rdma_ctx, &in_params, &out_params); |
---|
594 | | - if (rc) |
---|
| 645 | + if (rc) { |
---|
| 646 | + complete(&qp->iwarp_cm_comp); |
---|
595 | 647 | goto err; |
---|
| 648 | + } |
---|
596 | 649 | |
---|
597 | 650 | return rc; |
---|
598 | 651 | |
---|
599 | 652 | err: |
---|
600 | | - cm_id->rem_ref(cm_id); |
---|
601 | | - kfree(ep); |
---|
| 653 | + kref_put(&ep->refcnt, qedr_iw_free_ep); |
---|
602 | 654 | return rc; |
---|
603 | 655 | } |
---|
604 | 656 | |
---|
.. | .. |
---|
691 | 743 | |
---|
692 | 744 | DP_DEBUG(dev, QEDR_MSG_IWARP, "Accept on qpid=%d\n", conn_param->qpn); |
---|
693 | 745 | |
---|
694 | | - qp = idr_find(&dev->qpidr.idr, conn_param->qpn); |
---|
| 746 | + qp = qedr_iw_load_qp(dev, conn_param->qpn); |
---|
695 | 747 | if (!qp) { |
---|
696 | 748 | DP_ERR(dev, "Invalid QP number %d\n", conn_param->qpn); |
---|
697 | 749 | return -EINVAL; |
---|
698 | 750 | } |
---|
699 | 751 | |
---|
700 | 752 | ep->qp = qp; |
---|
701 | | - qp->ep = ep; |
---|
702 | 753 | cm_id->add_ref(cm_id); |
---|
703 | 754 | ep->cm_id = cm_id; |
---|
704 | 755 | |
---|
.. | .. |
---|
710 | 761 | params.ird = conn_param->ird; |
---|
711 | 762 | params.ord = conn_param->ord; |
---|
712 | 763 | |
---|
713 | | - ep->during_connect = 1; |
---|
| 764 | + if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT, |
---|
| 765 | + &qp->iwarp_cm_flags)) { |
---|
| 766 | + rc = -EINVAL; |
---|
| 767 | + goto err; /* QP already destroyed */ |
---|
| 768 | + } |
---|
| 769 | + |
---|
714 | 770 | rc = dev->ops->iwarp_accept(dev->rdma_ctx, ¶ms); |
---|
715 | | - if (rc) |
---|
| 771 | + if (rc) { |
---|
| 772 | + complete(&qp->iwarp_cm_comp); |
---|
716 | 773 | goto err; |
---|
| 774 | + } |
---|
717 | 775 | |
---|
718 | 776 | return rc; |
---|
| 777 | + |
---|
719 | 778 | err: |
---|
720 | | - ep->during_connect = 0; |
---|
721 | | - cm_id->rem_ref(cm_id); |
---|
| 779 | + kref_put(&ep->refcnt, qedr_iw_free_ep); |
---|
| 780 | + |
---|
722 | 781 | return rc; |
---|
723 | 782 | } |
---|
724 | 783 | |
---|
.. | .. |
---|
741 | 800 | { |
---|
742 | 801 | struct qedr_qp *qp = get_qedr_qp(ibqp); |
---|
743 | 802 | |
---|
744 | | - atomic_inc(&qp->refcnt); |
---|
| 803 | + kref_get(&qp->refcnt); |
---|
745 | 804 | } |
---|
746 | 805 | |
---|
747 | 806 | void qedr_iw_qp_rem_ref(struct ib_qp *ibqp) |
---|
748 | 807 | { |
---|
749 | 808 | struct qedr_qp *qp = get_qedr_qp(ibqp); |
---|
750 | 809 | |
---|
751 | | - if (atomic_dec_and_test(&qp->refcnt)) { |
---|
752 | | - spin_lock_irq(&qp->dev->qpidr.idr_lock); |
---|
753 | | - idr_remove(&qp->dev->qpidr.idr, qp->qp_id); |
---|
754 | | - spin_unlock_irq(&qp->dev->qpidr.idr_lock); |
---|
755 | | - kfree(qp); |
---|
756 | | - } |
---|
| 810 | + kref_put(&qp->refcnt, qedr_iw_free_qp); |
---|
757 | 811 | } |
---|
758 | 812 | |
---|
759 | 813 | struct ib_qp *qedr_iw_get_qp(struct ib_device *ibdev, int qpn) |
---|
760 | 814 | { |
---|
761 | 815 | struct qedr_dev *dev = get_qedr_dev(ibdev); |
---|
762 | 816 | |
---|
763 | | - return idr_find(&dev->qpidr.idr, qpn); |
---|
| 817 | + return xa_load(&dev->qps, qpn); |
---|
764 | 818 | } |
---|