Implement xarray based resource table ids for CQ, QP and MR. Implement Fifo for CQEs and QP's RQEs to be reused later in SRQ. Signed-off-by: Parav Pandit <parav@xxxxxxxxxxxx> --- drivers/infiniband/sw/loopback/helper.c | 139 +++++++++++++++++++++++ drivers/infiniband/sw/loopback/loopback_helper.h | 68 +++++++++++ 2 files changed, 207 insertions(+) create mode 100644 drivers/infiniband/sw/loopback/helper.c create mode 100644 drivers/infiniband/sw/loopback/loopback_helper.h 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 -- 1.8.3.1