diff --git a/drivers/infiniband/sw/loopback/helper.c b/drivers/infiniband/sw/loopback/helper.c
new file mode 100644
index 0000000..1294338
--- /dev/null
+++ b/drivers/infiniband/sw/loopback/helper.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2019 Mellanox Technologies. All rights reserved.
+ */
+
+#include <linux/xarray.h>
+#include <linux/refcount.h>
+#include "loopback_helper.h"
+
+void init_table(struct loopback_resource_table *table,
+		u32 min_id, u32 max_id, u32 id_mask, u8 id_shift)
+{
+	spin_lock_init(&table->lock);
+	xa_init_flags(&table->ids, XA_FLAGS_ALLOC);
+	table->max_id = max_id;
+	table->min_id = min_id;
+	table->id_mask = id_mask;
+	table->id_shift = id_shift;
+}
+
+void put_table_entry(struct loopback_resource *entry)
+{
+	if (refcount_dec_and_test(&entry->refcount))
+		complete(&entry->completion);
+}
+
+struct loopback_resource *
+get_table_entry_by_id(struct loopback_resource_table *table, u32 id)
+{
+	struct loopback_resource *entry;
+
+	id = (id & table->id_mask) >> table->id_shift;
+	rcu_read_lock();
+	entry = xa_load(&table->ids, id);
+	if (entry) {
+		if (!xa_get_mark(&table->ids, id,
+				 LOOPBACK_RESOURCE_STATE_VALID) ||
+		    !refcount_inc_not_zero(&entry->refcount))
+			entry = NULL;
+	}
+	rcu_read_unlock();
+	return entry;
+}
+
+int _attach_table_id(struct loopback_resource_table *table,
+		     struct loopback_resource *entry,
+		     int desired_id, bool valid)
+{
+	u32 start_id = table->min_id;
+	u32 stop_id = table->max_id;
+	int ret;
+
+	refcount_set(&entry->refcount, 1);
+	init_completion(&entry->completion);
+
+	if (desired_id > 0) {
+		/* need the exact match id */
+		start_id = desired_id << table->id_shift;
+		stop_id = desired_id << table->id_shift;
+	}
+	entry->id = start_id;
+	ret = xa_alloc(&table->ids, &entry->id, stop_id, entry, GFP_KERNEL);
+	if (ret)
+		return ret;
+	if (valid)
+		xa_set_mark(&table->ids, entry->id,
+			    LOOPBACK_RESOURCE_STATE_VALID);
+	return 0;
+}
+
+int attach_table_id_for_id(struct loopback_resource_table *table,
+			   struct loopback_resource *entry, int desired_id)
+{
+	return _attach_table_id(table, entry, desired_id, true);
+}
+
+int attach_table_id_free_state(struct loopback_resource_table *table,
+			       struct loopback_resource *entry)
+{
+	return _attach_table_id(table, entry, -1, false);
+}
+
+int attach_table_id(struct loopback_resource_table *table,
+		    struct loopback_resource *entry)
+{
+	return _attach_table_id(table, entry, -1, true);
+}
+
+void detach_table_id(struct loopback_resource_table *table,
+		     struct loopback_resource *entry)
+{
+	/* Mark entry invalid, so no new references can be taken */
+	xa_clear_mark(&table->ids, entry->id,
+		      LOOPBACK_RESOURCE_STATE_VALID);
+
+	/* Now wait for all readers to stop using the resource */
+	synchronize_rcu();
+
+	put_table_entry(entry);
+	wait_for_completion(&entry->completion);
+	/* At this point there cannot be any active reader */
+	WARN_ON(refcount_read(&entry->refcount));
+
+	/* Now that all references dropped, its free to reassign this id */
+	xa_erase(&table->ids, entry->id);
+}
+
+void init_fifo(struct loopback_fifo *fifo)
+{
+	spin_lock_init(&fifo->lock);
+	INIT_LIST_HEAD(&fifo->list);
+}
+
+void push_to_fifo(struct loopback_fifo *fifo, struct list_head *entry)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fifo->lock, flags);
+	list_add_tail(entry, &fifo->list);
+	fifo->entries++;
+	spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+struct list_head *pop_from_fifo(struct loopback_fifo *fifo)
+{
+	struct list_head *entry = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fifo->lock, flags);
+	if (!list_empty(&fifo->list)) {
+		entry = fifo->list.next;
+		list_del(fifo->list.next);
+		fifo->entries--;
+	}
+	if (!entry && fifo->entries)
+		pr_debug("%s fifo entries = %u\n", __func__,  fifo->entries);
+	spin_unlock_irqrestore(&fifo->lock, flags);
+	return entry;
+}
diff --git a/drivers/infiniband/sw/loopback/loopback_helper.h b/drivers/infiniband/sw/loopback/loopback_helper.h
new file mode 100644
index 0000000..8ea93f4
--- /dev/null
+++ b/drivers/infiniband/sw/loopback/loopback_helper.h
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2019 Mellanox Technologies. All rights reserved.
+ */
+
+#ifndef LOOPBACK_HELPER_H
+#define LOOPBACK_HELPER_H
+
+#include <linux/completion.h>
+struct loopback_resource {
+	struct completion completion;
+	/* wait for all datapath references to drop, we don't want to do
+	 * large memcpy while holding rcu, refcount doesn't hurt the
+	 * performance.
+	 */
+	refcount_t refcount;
+	u32 id;
+};
+
+#define LOOPBACK_RESOURCE_STATE_VALID XA_MARK_1
+
+/**
+ * struct loopback_resource_table - resource table
+ */
+
+struct loopback_resource_table {
+	/* Protects xarray of resources (ids) */
+	spinlock_t lock;
+	struct xarray ids;
+	u32 min_id;
+	u32 max_id;
+	u32 id_mask;
+	u8 id_shift;
+};
+
+/* TODO: replace with kernel pfifo, which consumes more memory */
+struct loopback_fifo {
+	/* Protect insert, remove to list */
+	spinlock_t lock;
+	/* head of entries, FIFO order */
+	struct list_head list;
+	u32 entries;
+};
+
+static inline u64 get_fifo_entries(struct loopback_fifo *fifo)
+{
+	return fifo->entries;
+}
+
+void init_fifo(struct loopback_fifo *fifo);
+void push_to_fifo(struct loopback_fifo *fifo, struct list_head *entry);
+struct list_head *pop_from_fifo(struct loopback_fifo *fifo);
+
+void init_table(struct loopback_resource_table *table,
+		u32 min_id, u32 max_id, u32 id_mask, u8 id_shift);
+struct loopback_resource *
+get_table_entry_by_id(struct loopback_resource_table *table, u32 id);
+void put_table_entry(struct loopback_resource *entry);
+int attach_table_id_for_id(struct loopback_resource_table *table,
+			   struct loopback_resource *entry, int desired_id);
+int attach_table_id_free_state(struct loopback_resource_table *table,
+			       struct loopback_resource *entry);
+int attach_table_id(struct loopback_resource_table *table,
+		    struct loopback_resource *entry);
+void detach_table_id(struct loopback_resource_table *table,
+		     struct loopback_resource *entry);
+
+#endif
