hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/infiniband/hw/qedr/qedr_iw_cm.c
....@@ -79,6 +79,27 @@
7979 }
8080 }
8181
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
+
82103 static void
83104 qedr_iw_mpa_request(void *context, struct qed_iwarp_cm_event_params *params)
84105 {
....@@ -93,6 +114,7 @@
93114
94115 ep->dev = dev;
95116 ep->qed_context = params->ep_context;
117
+ kref_init(&ep->refcnt);
96118
97119 memset(&event, 0, sizeof(event));
98120 event.event = IW_CM_EVENT_CONNECT_REQUEST;
....@@ -150,12 +172,10 @@
150172 {
151173 struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
152174
153
- if (ep->cm_id) {
175
+ if (ep->cm_id)
154176 qedr_iw_issue_event(context, params, IW_CM_EVENT_CLOSE);
155177
156
- ep->cm_id->rem_ref(ep->cm_id);
157
- ep->cm_id = NULL;
158
- }
178
+ kref_put(&ep->refcnt, qedr_iw_free_ep);
159179 }
160180
161181 static void
....@@ -195,11 +215,13 @@
195215 struct qedr_qp *qp = ep->qp;
196216 struct iw_cm_event event;
197217
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;
203225
204226 memset(&event, 0, sizeof(event));
205227 event.status = dwork->status;
....@@ -213,7 +235,6 @@
213235 else
214236 qp_params.new_state = QED_ROCE_QP_STATE_SQD;
215237
216
- kfree(dwork);
217238
218239 if (ep->cm_id)
219240 ep->cm_id->event_handler(ep->cm_id, &event);
....@@ -223,7 +244,10 @@
223244
224245 dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params);
225246
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);
227251 }
228252
229253 static void
....@@ -233,13 +257,17 @@
233257 struct qedr_discon_work *work;
234258 struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
235259 struct qedr_dev *dev = ep->dev;
236
- struct qedr_qp *qp = ep->qp;
237260
238261 work = kzalloc(sizeof(*work), GFP_ATOMIC);
239262 if (!work)
240263 return;
241264
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
+
243271 work->ep = ep;
244272 work->event = params->event;
245273 work->status = params->status;
....@@ -261,14 +289,28 @@
261289 if ((params->status == -ECONNREFUSED) && (!ep->qp)) {
262290 DP_DEBUG(dev, QEDR_MSG_IWARP,
263291 "PASSIVE connection refused releasing ep...\n");
264
- kfree(ep);
292
+ kref_put(&ep->refcnt, qedr_iw_free_ep);
265293 return;
266294 }
267295
296
+ complete(&ep->qp->iwarp_cm_comp);
268297 qedr_iw_issue_event(context, params, IW_CM_EVENT_ESTABLISHED);
269298
270299 if (params->status < 0)
271300 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);
272314 }
273315
274316 static int
....@@ -297,27 +339,15 @@
297339 qedr_iw_mpa_reply(context, params);
298340 break;
299341 case QED_IWARP_EVENT_PASSIVE_COMPLETE:
300
- ep->during_connect = 0;
301342 qedr_iw_passive_complete(context, params);
302343 break;
303
-
304344 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);
315346 break;
316347 case QED_IWARP_EVENT_DISCONNECT:
317348 qedr_iw_disconnect_event(context, params);
318349 break;
319350 case QED_IWARP_EVENT_CLOSE:
320
- ep->during_connect = 0;
321351 qedr_iw_close_event(context, params);
322352 break;
323353 case QED_IWARP_EVENT_RQ_EMPTY:
....@@ -358,7 +388,7 @@
358388 default:
359389 DP_NOTICE(dev, "Unknown event received %d\n", params->event);
360390 break;
361
- };
391
+ }
362392 return 0;
363393 }
364394
....@@ -485,6 +515,19 @@
485515 return rc;
486516 }
487517
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
+
488531 int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
489532 {
490533 struct qedr_dev *dev = get_qedr_dev(cm_id->device);
....@@ -499,10 +542,6 @@
499542 struct qedr_qp *qp;
500543 int rc = 0;
501544 int i;
502
-
503
- qp = idr_find(&dev->qpidr.idr, conn_param->qpn);
504
- if (unlikely(!qp))
505
- return -EINVAL;
506545
507546 laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
508547 raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
....@@ -525,8 +564,15 @@
525564 return -ENOMEM;
526565
527566 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
+
528575 ep->qp = qp;
529
- qp->ep = ep;
530576 cm_id->add_ref(cm_id);
531577 ep->cm_id = cm_id;
532578
....@@ -589,16 +635,22 @@
589635 in_params.qp = qp->qed_qp;
590636 memcpy(in_params.local_mac_addr, dev->ndev->dev_addr, ETH_ALEN);
591637
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
+
593644 rc = dev->ops->iwarp_connect(dev->rdma_ctx, &in_params, &out_params);
594
- if (rc)
645
+ if (rc) {
646
+ complete(&qp->iwarp_cm_comp);
595647 goto err;
648
+ }
596649
597650 return rc;
598651
599652 err:
600
- cm_id->rem_ref(cm_id);
601
- kfree(ep);
653
+ kref_put(&ep->refcnt, qedr_iw_free_ep);
602654 return rc;
603655 }
604656
....@@ -691,14 +743,13 @@
691743
692744 DP_DEBUG(dev, QEDR_MSG_IWARP, "Accept on qpid=%d\n", conn_param->qpn);
693745
694
- qp = idr_find(&dev->qpidr.idr, conn_param->qpn);
746
+ qp = qedr_iw_load_qp(dev, conn_param->qpn);
695747 if (!qp) {
696748 DP_ERR(dev, "Invalid QP number %d\n", conn_param->qpn);
697749 return -EINVAL;
698750 }
699751
700752 ep->qp = qp;
701
- qp->ep = ep;
702753 cm_id->add_ref(cm_id);
703754 ep->cm_id = cm_id;
704755
....@@ -710,15 +761,23 @@
710761 params.ird = conn_param->ird;
711762 params.ord = conn_param->ord;
712763
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
+
714770 rc = dev->ops->iwarp_accept(dev->rdma_ctx, &params);
715
- if (rc)
771
+ if (rc) {
772
+ complete(&qp->iwarp_cm_comp);
716773 goto err;
774
+ }
717775
718776 return rc;
777
+
719778 err:
720
- ep->during_connect = 0;
721
- cm_id->rem_ref(cm_id);
779
+ kref_put(&ep->refcnt, qedr_iw_free_ep);
780
+
722781 return rc;
723782 }
724783
....@@ -741,24 +800,19 @@
741800 {
742801 struct qedr_qp *qp = get_qedr_qp(ibqp);
743802
744
- atomic_inc(&qp->refcnt);
803
+ kref_get(&qp->refcnt);
745804 }
746805
747806 void qedr_iw_qp_rem_ref(struct ib_qp *ibqp)
748807 {
749808 struct qedr_qp *qp = get_qedr_qp(ibqp);
750809
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);
757811 }
758812
759813 struct ib_qp *qedr_iw_get_qp(struct ib_device *ibdev, int qpn)
760814 {
761815 struct qedr_dev *dev = get_qedr_dev(ibdev);
762816
763
- return idr_find(&dev->qpidr.idr, qpn);
817
+ return xa_load(&dev->qps, qpn);
764818 }