*
  * Clean up all resources associated with the connection and release
  * the initial reference taken by iw_create_cm_id.
+ *
+ * Returns true if and only if the last cm_id_priv reference has been dropped.
  */
-static void destroy_cm_id(struct iw_cm_id *cm_id)
+static bool destroy_cm_id(struct iw_cm_id *cm_id)
 {
        struct iwcm_id_private *cm_id_priv;
        struct ib_qp *qp;
                iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
        }
 
-       (void)iwcm_deref_id(cm_id_priv);
+       return iwcm_deref_id(cm_id_priv);
 }
 
 /*
  */
 void iw_destroy_cm_id(struct iw_cm_id *cm_id)
 {
-       destroy_cm_id(cm_id);
+       if (!destroy_cm_id(cm_id))
+               flush_workqueue(iwcm_wq);
 }
 EXPORT_SYMBOL(iw_destroy_cm_id);
 
                if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
                        ret = process_event(cm_id_priv, &levent);
                        if (ret)
-                               destroy_cm_id(&cm_id_priv->id);
+                               WARN_ON_ONCE(destroy_cm_id(&cm_id_priv->id));
                } else
                        pr_debug("dropping event %d\n", levent.event);
                if (iwcm_deref_id(cm_id_priv))