[RFC PATCH 02/13] drivers: ultraeth: add context support

Nikolay Aleksandrov
2025-03-06T23:04:02Z

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@enfabrica.net>
Signed-off-by: Alex Badea <alex.badea@keysight.com>
---
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