xref: /linux/drivers/dibs/dibs_main.c (revision 69baaac9361edd169713562f088829a1be9c51a9)
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 
18cb990a45SAlexandra Winter #include "dibs_loopback.h"
19cb990a45SAlexandra 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 {
39*69baaac9SAlexandra Winter 	struct dibs_dev *dibs;
40d324a2caSAlexandra Winter 	int i, rc = -ENOSPC;
41d324a2caSAlexandra Winter 
42*69baaac9SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
43d324a2caSAlexandra Winter 	mutex_lock(&clients_lock);
44d324a2caSAlexandra Winter 	for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
45d324a2caSAlexandra Winter 		if (!clients[i]) {
46d324a2caSAlexandra Winter 			clients[i] = client;
47d324a2caSAlexandra Winter 			client->id = i;
48d324a2caSAlexandra Winter 			if (i == max_client)
49d324a2caSAlexandra Winter 				max_client++;
50d324a2caSAlexandra Winter 			rc = 0;
51d324a2caSAlexandra Winter 			break;
52d324a2caSAlexandra Winter 		}
53d324a2caSAlexandra Winter 	}
54d324a2caSAlexandra Winter 	mutex_unlock(&clients_lock);
55d324a2caSAlexandra Winter 
56*69baaac9SAlexandra Winter 	if (i < MAX_DIBS_CLIENTS) {
57*69baaac9SAlexandra Winter 		/* initialize with all devices that we got so far */
58*69baaac9SAlexandra Winter 		list_for_each_entry(dibs, &dibs_dev_list.list, list) {
59*69baaac9SAlexandra Winter 			dibs->priv[i] = NULL;
60*69baaac9SAlexandra Winter 			client->ops->add_dev(dibs);
61*69baaac9SAlexandra Winter 		}
62*69baaac9SAlexandra Winter 	}
63*69baaac9SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
64*69baaac9SAlexandra Winter 
65d324a2caSAlexandra Winter 	return rc;
66d324a2caSAlexandra Winter }
67d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_register_client);
68d324a2caSAlexandra Winter 
69d324a2caSAlexandra Winter int dibs_unregister_client(struct dibs_client *client)
70d324a2caSAlexandra Winter {
71*69baaac9SAlexandra Winter 	struct dibs_dev *dibs;
72d324a2caSAlexandra Winter 	int rc = 0;
73d324a2caSAlexandra Winter 
74*69baaac9SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
75*69baaac9SAlexandra Winter 	list_for_each_entry(dibs, &dibs_dev_list.list, list) {
76*69baaac9SAlexandra Winter 		clients[client->id]->ops->del_dev(dibs);
77*69baaac9SAlexandra Winter 		dibs->priv[client->id] = NULL;
78*69baaac9SAlexandra Winter 	}
79*69baaac9SAlexandra Winter 
80d324a2caSAlexandra Winter 	mutex_lock(&clients_lock);
81d324a2caSAlexandra Winter 	clients[client->id] = NULL;
82d324a2caSAlexandra Winter 	if (client->id + 1 == max_client)
83d324a2caSAlexandra Winter 		max_client--;
84d324a2caSAlexandra Winter 	mutex_unlock(&clients_lock);
85*69baaac9SAlexandra Winter 
86*69baaac9SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
87d324a2caSAlexandra Winter 	return rc;
88d324a2caSAlexandra Winter }
89d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_unregister_client);
9035758b00SAlexandra Winter 
9126972696SAlexandra Winter struct dibs_dev *dibs_dev_alloc(void)
9226972696SAlexandra Winter {
9326972696SAlexandra Winter 	struct dibs_dev *dibs;
9426972696SAlexandra Winter 
9526972696SAlexandra Winter 	dibs = kzalloc(sizeof(*dibs), GFP_KERNEL);
9626972696SAlexandra Winter 
9726972696SAlexandra Winter 	return dibs;
9826972696SAlexandra Winter }
9926972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_alloc);
10026972696SAlexandra Winter 
10126972696SAlexandra Winter int dibs_dev_add(struct dibs_dev *dibs)
10226972696SAlexandra Winter {
103*69baaac9SAlexandra Winter 	int i;
104*69baaac9SAlexandra Winter 
10526972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
106*69baaac9SAlexandra Winter 	mutex_lock(&clients_lock);
107*69baaac9SAlexandra Winter 	for (i = 0; i < max_client; ++i) {
108*69baaac9SAlexandra Winter 		if (clients[i])
109*69baaac9SAlexandra Winter 			clients[i]->ops->add_dev(dibs);
110*69baaac9SAlexandra Winter 	}
111*69baaac9SAlexandra Winter 	mutex_unlock(&clients_lock);
11226972696SAlexandra Winter 	list_add(&dibs->list, &dibs_dev_list.list);
11326972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
11426972696SAlexandra Winter 
11526972696SAlexandra Winter 	return 0;
11626972696SAlexandra Winter }
11726972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_add);
11826972696SAlexandra Winter 
11926972696SAlexandra Winter void dibs_dev_del(struct dibs_dev *dibs)
12026972696SAlexandra Winter {
121*69baaac9SAlexandra Winter 	int i;
122*69baaac9SAlexandra Winter 
12326972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
124*69baaac9SAlexandra Winter 	mutex_lock(&clients_lock);
125*69baaac9SAlexandra Winter 	for (i = 0; i < max_client; ++i) {
126*69baaac9SAlexandra Winter 		if (clients[i])
127*69baaac9SAlexandra Winter 			clients[i]->ops->del_dev(dibs);
128*69baaac9SAlexandra Winter 	}
129*69baaac9SAlexandra Winter 	mutex_unlock(&clients_lock);
13026972696SAlexandra Winter 	list_del_init(&dibs->list);
13126972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
13226972696SAlexandra Winter }
13326972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_del);
13426972696SAlexandra Winter 
13535758b00SAlexandra Winter static int __init dibs_init(void)
13635758b00SAlexandra Winter {
137cb990a45SAlexandra Winter 	int rc;
138cb990a45SAlexandra Winter 
13935758b00SAlexandra Winter 	memset(clients, 0, sizeof(clients));
14035758b00SAlexandra Winter 	max_client = 0;
14135758b00SAlexandra Winter 
142cb990a45SAlexandra Winter 	rc = dibs_loopback_init();
143cb990a45SAlexandra Winter 	if (rc)
144cb990a45SAlexandra Winter 		pr_err("%s fails with %d\n", __func__, rc);
145cb990a45SAlexandra Winter 
146cb990a45SAlexandra Winter 	return rc;
14735758b00SAlexandra Winter }
14835758b00SAlexandra Winter 
14935758b00SAlexandra Winter static void __exit dibs_exit(void)
15035758b00SAlexandra Winter {
151cb990a45SAlexandra Winter 	dibs_loopback_exit();
15235758b00SAlexandra Winter }
15335758b00SAlexandra Winter 
15435758b00SAlexandra Winter module_init(dibs_init);
15535758b00SAlexandra Winter module_exit(dibs_exit);
156