xref: /linux/drivers/dibs/dibs_main.c (revision 845c334a0186a23c2ac4abfb444e499fec831b24)
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 {
3969baaac9SAlexandra Winter 	struct dibs_dev *dibs;
40d324a2caSAlexandra Winter 	int i, rc = -ENOSPC;
41d324a2caSAlexandra Winter 
4269baaac9SAlexandra 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 
5669baaac9SAlexandra Winter 	if (i < MAX_DIBS_CLIENTS) {
5769baaac9SAlexandra Winter 		/* initialize with all devices that we got so far */
5869baaac9SAlexandra Winter 		list_for_each_entry(dibs, &dibs_dev_list.list, list) {
5969baaac9SAlexandra Winter 			dibs->priv[i] = NULL;
6069baaac9SAlexandra Winter 			client->ops->add_dev(dibs);
6169baaac9SAlexandra Winter 		}
6269baaac9SAlexandra Winter 	}
6369baaac9SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
6469baaac9SAlexandra 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 {
7169baaac9SAlexandra Winter 	struct dibs_dev *dibs;
72d324a2caSAlexandra Winter 	int rc = 0;
73d324a2caSAlexandra Winter 
7469baaac9SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
7569baaac9SAlexandra Winter 	list_for_each_entry(dibs, &dibs_dev_list.list, list) {
7669baaac9SAlexandra Winter 		clients[client->id]->ops->del_dev(dibs);
7769baaac9SAlexandra Winter 		dibs->priv[client->id] = NULL;
7869baaac9SAlexandra Winter 	}
7969baaac9SAlexandra 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);
8569baaac9SAlexandra Winter 
8669baaac9SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
87d324a2caSAlexandra Winter 	return rc;
88d324a2caSAlexandra Winter }
89d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_unregister_client);
9035758b00SAlexandra Winter 
91*845c334aSJulian Ruess static void dibs_dev_release(struct device *dev)
92*845c334aSJulian Ruess {
93*845c334aSJulian Ruess 	struct dibs_dev *dibs;
94*845c334aSJulian Ruess 
95*845c334aSJulian Ruess 	dibs = container_of(dev, struct dibs_dev, dev);
96*845c334aSJulian Ruess 
97*845c334aSJulian Ruess 	kfree(dibs);
98*845c334aSJulian Ruess }
99*845c334aSJulian Ruess 
10026972696SAlexandra Winter struct dibs_dev *dibs_dev_alloc(void)
10126972696SAlexandra Winter {
10226972696SAlexandra Winter 	struct dibs_dev *dibs;
10326972696SAlexandra Winter 
10426972696SAlexandra Winter 	dibs = kzalloc(sizeof(*dibs), GFP_KERNEL);
105*845c334aSJulian Ruess 	if (!dibs)
106*845c334aSJulian Ruess 		return dibs;
107*845c334aSJulian Ruess 	dibs->dev.release = dibs_dev_release;
108*845c334aSJulian Ruess 	device_initialize(&dibs->dev);
10926972696SAlexandra Winter 
11026972696SAlexandra Winter 	return dibs;
11126972696SAlexandra Winter }
11226972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_alloc);
11326972696SAlexandra Winter 
11426972696SAlexandra Winter int dibs_dev_add(struct dibs_dev *dibs)
11526972696SAlexandra Winter {
116*845c334aSJulian Ruess 	int i, ret;
117*845c334aSJulian Ruess 
118*845c334aSJulian Ruess 	ret = device_add(&dibs->dev);
119*845c334aSJulian Ruess 	if (ret)
120*845c334aSJulian Ruess 		return ret;
12169baaac9SAlexandra Winter 
12226972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
12369baaac9SAlexandra Winter 	mutex_lock(&clients_lock);
12469baaac9SAlexandra Winter 	for (i = 0; i < max_client; ++i) {
12569baaac9SAlexandra Winter 		if (clients[i])
12669baaac9SAlexandra Winter 			clients[i]->ops->add_dev(dibs);
12769baaac9SAlexandra Winter 	}
12869baaac9SAlexandra Winter 	mutex_unlock(&clients_lock);
12926972696SAlexandra Winter 	list_add(&dibs->list, &dibs_dev_list.list);
13026972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
13126972696SAlexandra Winter 
13226972696SAlexandra Winter 	return 0;
13326972696SAlexandra Winter }
13426972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_add);
13526972696SAlexandra Winter 
13626972696SAlexandra Winter void dibs_dev_del(struct dibs_dev *dibs)
13726972696SAlexandra Winter {
13869baaac9SAlexandra Winter 	int i;
13969baaac9SAlexandra Winter 
14026972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
14169baaac9SAlexandra Winter 	mutex_lock(&clients_lock);
14269baaac9SAlexandra Winter 	for (i = 0; i < max_client; ++i) {
14369baaac9SAlexandra Winter 		if (clients[i])
14469baaac9SAlexandra Winter 			clients[i]->ops->del_dev(dibs);
14569baaac9SAlexandra Winter 	}
14669baaac9SAlexandra Winter 	mutex_unlock(&clients_lock);
14726972696SAlexandra Winter 	list_del_init(&dibs->list);
14826972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
149*845c334aSJulian Ruess 
150*845c334aSJulian Ruess 	device_del(&dibs->dev);
15126972696SAlexandra Winter }
15226972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_del);
15326972696SAlexandra Winter 
15435758b00SAlexandra Winter static int __init dibs_init(void)
15535758b00SAlexandra Winter {
156cb990a45SAlexandra Winter 	int rc;
157cb990a45SAlexandra Winter 
15835758b00SAlexandra Winter 	memset(clients, 0, sizeof(clients));
15935758b00SAlexandra Winter 	max_client = 0;
16035758b00SAlexandra Winter 
161cb990a45SAlexandra Winter 	rc = dibs_loopback_init();
162cb990a45SAlexandra Winter 	if (rc)
163cb990a45SAlexandra Winter 		pr_err("%s fails with %d\n", __func__, rc);
164cb990a45SAlexandra Winter 
165cb990a45SAlexandra Winter 	return rc;
16635758b00SAlexandra Winter }
16735758b00SAlexandra Winter 
16835758b00SAlexandra Winter static void __exit dibs_exit(void)
16935758b00SAlexandra Winter {
170cb990a45SAlexandra Winter 	dibs_loopback_exit();
17135758b00SAlexandra Winter }
17235758b00SAlexandra Winter 
17335758b00SAlexandra Winter module_init(dibs_init);
17435758b00SAlexandra Winter module_exit(dibs_exit);
175