xref: /linux/drivers/dibs/dibs_main.c (revision cb990a45d7f6eb6dc495d2226a3005b284a5ee4f)
135758b00SAlexandra Winter // SPDX-License-Identifier: GPL-2.0
235758b00SAlexandra Winter /*
335758b00SAlexandra Winter  *  DIBS - Direct Internal Buffer Sharing
435758b00SAlexandra Winter  *
535758b00SAlexandra Winter  *  Implementation of the DIBS class module
635758b00SAlexandra Winter  *
735758b00SAlexandra Winter  *  Copyright IBM Corp. 2025
835758b00SAlexandra Winter  */
935758b00SAlexandra Winter #define KMSG_COMPONENT "dibs"
1035758b00SAlexandra Winter #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1135758b00SAlexandra Winter 
1235758b00SAlexandra Winter #include <linux/module.h>
1335758b00SAlexandra Winter #include <linux/types.h>
1426972696SAlexandra Winter #include <linux/slab.h>
1535758b00SAlexandra Winter #include <linux/err.h>
1635758b00SAlexandra Winter #include <linux/dibs.h>
1735758b00SAlexandra Winter 
18*cb990a45SAlexandra Winter #include "dibs_loopback.h"
19*cb990a45SAlexandra Winter 
2035758b00SAlexandra Winter MODULE_DESCRIPTION("Direct Internal Buffer Sharing class");
2135758b00SAlexandra Winter MODULE_LICENSE("GPL");
2235758b00SAlexandra Winter 
2335758b00SAlexandra Winter /* use an array rather a list for fast mapping: */
2435758b00SAlexandra Winter static struct dibs_client *clients[MAX_DIBS_CLIENTS];
2535758b00SAlexandra Winter static u8 max_client;
26d324a2caSAlexandra Winter static DEFINE_MUTEX(clients_lock);
2726972696SAlexandra Winter struct dibs_dev_list {
2826972696SAlexandra Winter 	struct list_head list;
2926972696SAlexandra Winter 	struct mutex mutex; /* protects dibs device list */
3026972696SAlexandra Winter };
3126972696SAlexandra Winter 
3226972696SAlexandra Winter static struct dibs_dev_list dibs_dev_list = {
3326972696SAlexandra Winter 	.list = LIST_HEAD_INIT(dibs_dev_list.list),
3426972696SAlexandra Winter 	.mutex = __MUTEX_INITIALIZER(dibs_dev_list.mutex),
3526972696SAlexandra Winter };
36d324a2caSAlexandra Winter 
37d324a2caSAlexandra Winter int dibs_register_client(struct dibs_client *client)
38d324a2caSAlexandra Winter {
39d324a2caSAlexandra Winter 	int i, rc = -ENOSPC;
40d324a2caSAlexandra Winter 
41d324a2caSAlexandra Winter 	mutex_lock(&clients_lock);
42d324a2caSAlexandra Winter 	for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
43d324a2caSAlexandra Winter 		if (!clients[i]) {
44d324a2caSAlexandra Winter 			clients[i] = client;
45d324a2caSAlexandra Winter 			client->id = i;
46d324a2caSAlexandra Winter 			if (i == max_client)
47d324a2caSAlexandra Winter 				max_client++;
48d324a2caSAlexandra Winter 			rc = 0;
49d324a2caSAlexandra Winter 			break;
50d324a2caSAlexandra Winter 		}
51d324a2caSAlexandra Winter 	}
52d324a2caSAlexandra Winter 	mutex_unlock(&clients_lock);
53d324a2caSAlexandra Winter 
54d324a2caSAlexandra Winter 	return rc;
55d324a2caSAlexandra Winter }
56d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_register_client);
57d324a2caSAlexandra Winter 
58d324a2caSAlexandra Winter int dibs_unregister_client(struct dibs_client *client)
59d324a2caSAlexandra Winter {
60d324a2caSAlexandra Winter 	int rc = 0;
61d324a2caSAlexandra Winter 
62d324a2caSAlexandra Winter 	mutex_lock(&clients_lock);
63d324a2caSAlexandra Winter 	clients[client->id] = NULL;
64d324a2caSAlexandra Winter 	if (client->id + 1 == max_client)
65d324a2caSAlexandra Winter 		max_client--;
66d324a2caSAlexandra Winter 	mutex_unlock(&clients_lock);
67d324a2caSAlexandra Winter 	return rc;
68d324a2caSAlexandra Winter }
69d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_unregister_client);
7035758b00SAlexandra Winter 
7126972696SAlexandra Winter struct dibs_dev *dibs_dev_alloc(void)
7226972696SAlexandra Winter {
7326972696SAlexandra Winter 	struct dibs_dev *dibs;
7426972696SAlexandra Winter 
7526972696SAlexandra Winter 	dibs = kzalloc(sizeof(*dibs), GFP_KERNEL);
7626972696SAlexandra Winter 
7726972696SAlexandra Winter 	return dibs;
7826972696SAlexandra Winter }
7926972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_alloc);
8026972696SAlexandra Winter 
8126972696SAlexandra Winter int dibs_dev_add(struct dibs_dev *dibs)
8226972696SAlexandra Winter {
8326972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
8426972696SAlexandra Winter 	list_add(&dibs->list, &dibs_dev_list.list);
8526972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
8626972696SAlexandra Winter 
8726972696SAlexandra Winter 	return 0;
8826972696SAlexandra Winter }
8926972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_add);
9026972696SAlexandra Winter 
9126972696SAlexandra Winter void dibs_dev_del(struct dibs_dev *dibs)
9226972696SAlexandra Winter {
9326972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
9426972696SAlexandra Winter 	list_del_init(&dibs->list);
9526972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
9626972696SAlexandra Winter }
9726972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_del);
9826972696SAlexandra Winter 
9935758b00SAlexandra Winter static int __init dibs_init(void)
10035758b00SAlexandra Winter {
101*cb990a45SAlexandra Winter 	int rc;
102*cb990a45SAlexandra Winter 
10335758b00SAlexandra Winter 	memset(clients, 0, sizeof(clients));
10435758b00SAlexandra Winter 	max_client = 0;
10535758b00SAlexandra Winter 
106*cb990a45SAlexandra Winter 	rc = dibs_loopback_init();
107*cb990a45SAlexandra Winter 	if (rc)
108*cb990a45SAlexandra Winter 		pr_err("%s fails with %d\n", __func__, rc);
109*cb990a45SAlexandra Winter 
110*cb990a45SAlexandra Winter 	return rc;
11135758b00SAlexandra Winter }
11235758b00SAlexandra Winter 
11335758b00SAlexandra Winter static void __exit dibs_exit(void)
11435758b00SAlexandra Winter {
115*cb990a45SAlexandra Winter 	dibs_loopback_exit();
11635758b00SAlexandra Winter }
11735758b00SAlexandra Winter 
11835758b00SAlexandra Winter module_init(dibs_init);
11935758b00SAlexandra Winter module_exit(dibs_exit);
120