The ultra ethernet context is at the root and must be created first. UET contexts are identified by host unique assigned ids on creation and are protected by a ref counter. Signed-off-by: Nikolay Aleksandrov <nikolay@xxxxxxxxxxxxx> Signed-off-by: Alex Badea <alex.badea@xxxxxxxxxxxx> --- drivers/ultraeth/Makefile | 2 +- drivers/ultraeth/uet_context.c | 149 +++++++++++++++++++++++++++++ drivers/ultraeth/uet_main.c | 2 + include/net/ultraeth/uet_context.h | 27 ++++++ 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 drivers/ultraeth/uet_context.c create mode 100644 include/net/ultraeth/uet_context.h diff --git a/drivers/ultraeth/Makefile b/drivers/ultraeth/Makefile index e30373d4b5dc..dc0c07eeef65 100644 --- a/drivers/ultraeth/Makefile +++ b/drivers/ultraeth/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_ULTRAETH) += ultraeth.o -ultraeth-objs := uet_main.o +ultraeth-objs := uet_main.o uet_context.o diff --git a/drivers/ultraeth/uet_context.c b/drivers/ultraeth/uet_context.c new file mode 100644 index 000000000000..1c74cd8bbd56 --- /dev/null +++ b/drivers/ultraeth/uet_context.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +#include <net/ultraeth/uet_context.h> + +#define MAX_CONTEXT_ID 256 +static DECLARE_BITMAP(uet_context_ids, MAX_CONTEXT_ID); +static LIST_HEAD(uet_context_list); +static DEFINE_MUTEX(uet_context_lock); + +static int uet_context_get_new_id(int id) +{ + if (WARN_ON(id < -1 || id >= MAX_CONTEXT_ID)) + return -EINVAL; + + mutex_lock(&uet_context_lock); + if (id == -1) + id = find_first_zero_bit(uet_context_ids, MAX_CONTEXT_ID); + if (id < MAX_CONTEXT_ID) { + if (test_and_set_bit(id, uet_context_ids)) + id = -EBUSY; + } else { + id = -ENOSPC; + } + mutex_unlock(&uet_context_lock); + + return id; +} + +static void uet_context_put_id(struct uet_context *ctx) +{ + clear_bit(ctx->id, uet_context_ids); +} + +static void uet_context_link(struct uet_context *ctx) +{ + WARN_ON(!list_empty(&ctx->list)); + list_add(&ctx->list, &uet_context_list); +} + +static void uet_context_unlink(struct uet_context *ctx) +{ + list_del_init(&ctx->list); + if (refcount_dec_and_test(&ctx->refcnt)) + return; + + mutex_unlock(&uet_context_lock); + wait_event(ctx->refcnt_wait, refcount_read(&ctx->refcnt) == 0); + mutex_lock(&uet_context_lock); + WARN_ON(refcount_read(&ctx->refcnt) > 0); +} + +static struct uet_context *uet_context_find(int id) +{ + struct uet_context *ctx; + + if (!test_bit(id, uet_context_ids)) + return NULL; + + list_for_each_entry(ctx, &uet_context_list, list) + if (ctx->id == id) + return ctx; + + return NULL; +} + +struct uet_context *uet_context_get_by_id(int id) +{ + struct uet_context *ctx; + + mutex_lock(&uet_context_lock); + ctx = uet_context_find(id); + if (ctx) + refcount_inc(&ctx->refcnt); + mutex_unlock(&uet_context_lock); + + return ctx; +} + +void uet_context_put(struct uet_context *ctx) +{ + if (refcount_dec_and_test(&ctx->refcnt)) + wake_up(&ctx->refcnt_wait); +} + +int uet_context_create(int id) +{ + struct uet_context *ctx; + int err = -ENOMEM; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return err; + + INIT_LIST_HEAD(&ctx->list); + init_waitqueue_head(&ctx->refcnt_wait); + refcount_set(&ctx->refcnt, 1); + + ctx->id = uet_context_get_new_id(id); + if (ctx->id < 0) { + err = ctx->id; + goto ctx_id_err; + } + + uet_context_link(ctx); + + return 0; + +ctx_id_err: + kfree(ctx); + + return err; +} + +static void __uet_context_destroy(struct uet_context *ctx) +{ + uet_context_unlink(ctx); + uet_context_put_id(ctx); + kfree(ctx); +} + +bool uet_context_destroy(int id) +{ + struct uet_context *ctx; + bool found = false; + + mutex_lock(&uet_context_lock); + ctx = uet_context_find(id); + if (ctx) { + __uet_context_destroy(ctx); + found = true; + } + mutex_unlock(&uet_context_lock); + + return found; +} + +void uet_context_destroy_all(void) +{ + struct uet_context *ctx; + + mutex_lock(&uet_context_lock); + while ((ctx = list_first_entry_or_null(&uet_context_list, + struct uet_context, + list))) + __uet_context_destroy(ctx); + + WARN_ON(!list_empty(&uet_context_list)); + mutex_unlock(&uet_context_lock); +} diff --git a/drivers/ultraeth/uet_main.c b/drivers/ultraeth/uet_main.c index 0d74175fc047..0f8383c6aba0 100644 --- a/drivers/ultraeth/uet_main.c +++ b/drivers/ultraeth/uet_main.c @@ -3,6 +3,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> +#include <net/ultraeth/uet_context.h> static int __init uet_init(void) { @@ -11,6 +12,7 @@ static int __init uet_init(void) static void __exit uet_exit(void) { + uet_context_destroy_all(); } module_init(uet_init); diff --git a/include/net/ultraeth/uet_context.h b/include/net/ultraeth/uet_context.h new file mode 100644 index 000000000000..150ad2c9b456 --- /dev/null +++ b/include/net/ultraeth/uet_context.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ + +#ifndef _UET_CONTEXT_H +#define _UET_CONTEXT_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/refcount.h> +#include <linux/wait.h> + +struct uet_context { + int id; + refcount_t refcnt; + wait_queue_head_t refcnt_wait; + struct list_head list; +}; + +struct uet_context *uet_context_get_by_id(int id); +void uet_context_put(struct uet_context *ses_pl); + +int uet_context_create(int id); +bool uet_context_destroy(int id); +void uet_context_destroy_all(void); + +#endif /* _UET_CONTEXT_H */ -- 2.48.1