xref: /linux/drivers/dibs/dibs_main.c (revision 845c334a0186a23c2ac4abfb444e499fec831b24)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  DIBS - Direct Internal Buffer Sharing
4  *
5  *  Implementation of the DIBS class module
6  *
7  *  Copyright IBM Corp. 2025
8  */
9 #define KMSG_COMPONENT "dibs"
10 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11 
12 #include <linux/module.h>
13 #include <linux/types.h>
14 #include <linux/slab.h>
15 #include <linux/err.h>
16 #include <linux/dibs.h>
17 
18 #include "dibs_loopback.h"
19 
20 MODULE_DESCRIPTION("Direct Internal Buffer Sharing class");
21 MODULE_LICENSE("GPL");
22 
23 /* use an array rather a list for fast mapping: */
24 static struct dibs_client *clients[MAX_DIBS_CLIENTS];
25 static u8 max_client;
26 static DEFINE_MUTEX(clients_lock);
27 struct dibs_dev_list {
28 	struct list_head list;
29 	struct mutex mutex; /* protects dibs device list */
30 };
31 
32 static struct dibs_dev_list dibs_dev_list = {
33 	.list = LIST_HEAD_INIT(dibs_dev_list.list),
34 	.mutex = __MUTEX_INITIALIZER(dibs_dev_list.mutex),
35 };
36 
37 int dibs_register_client(struct dibs_client *client)
38 {
39 	struct dibs_dev *dibs;
40 	int i, rc = -ENOSPC;
41 
42 	mutex_lock(&dibs_dev_list.mutex);
43 	mutex_lock(&clients_lock);
44 	for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
45 		if (!clients[i]) {
46 			clients[i] = client;
47 			client->id = i;
48 			if (i == max_client)
49 				max_client++;
50 			rc = 0;
51 			break;
52 		}
53 	}
54 	mutex_unlock(&clients_lock);
55 
56 	if (i < MAX_DIBS_CLIENTS) {
57 		/* initialize with all devices that we got so far */
58 		list_for_each_entry(dibs, &dibs_dev_list.list, list) {
59 			dibs->priv[i] = NULL;
60 			client->ops->add_dev(dibs);
61 		}
62 	}
63 	mutex_unlock(&dibs_dev_list.mutex);
64 
65 	return rc;
66 }
67 EXPORT_SYMBOL_GPL(dibs_register_client);
68 
69 int dibs_unregister_client(struct dibs_client *client)
70 {
71 	struct dibs_dev *dibs;
72 	int rc = 0;
73 
74 	mutex_lock(&dibs_dev_list.mutex);
75 	list_for_each_entry(dibs, &dibs_dev_list.list, list) {
76 		clients[client->id]->ops->del_dev(dibs);
77 		dibs->priv[client->id] = NULL;
78 	}
79 
80 	mutex_lock(&clients_lock);
81 	clients[client->id] = NULL;
82 	if (client->id + 1 == max_client)
83 		max_client--;
84 	mutex_unlock(&clients_lock);
85 
86 	mutex_unlock(&dibs_dev_list.mutex);
87 	return rc;
88 }
89 EXPORT_SYMBOL_GPL(dibs_unregister_client);
90 
91 static void dibs_dev_release(struct device *dev)
92 {
93 	struct dibs_dev *dibs;
94 
95 	dibs = container_of(dev, struct dibs_dev, dev);
96 
97 	kfree(dibs);
98 }
99 
100 struct dibs_dev *dibs_dev_alloc(void)
101 {
102 	struct dibs_dev *dibs;
103 
104 	dibs = kzalloc(sizeof(*dibs), GFP_KERNEL);
105 	if (!dibs)
106 		return dibs;
107 	dibs->dev.release = dibs_dev_release;
108 	device_initialize(&dibs->dev);
109 
110 	return dibs;
111 }
112 EXPORT_SYMBOL_GPL(dibs_dev_alloc);
113 
114 int dibs_dev_add(struct dibs_dev *dibs)
115 {
116 	int i, ret;
117 
118 	ret = device_add(&dibs->dev);
119 	if (ret)
120 		return ret;
121 
122 	mutex_lock(&dibs_dev_list.mutex);
123 	mutex_lock(&clients_lock);
124 	for (i = 0; i < max_client; ++i) {
125 		if (clients[i])
126 			clients[i]->ops->add_dev(dibs);
127 	}
128 	mutex_unlock(&clients_lock);
129 	list_add(&dibs->list, &dibs_dev_list.list);
130 	mutex_unlock(&dibs_dev_list.mutex);
131 
132 	return 0;
133 }
134 EXPORT_SYMBOL_GPL(dibs_dev_add);
135 
136 void dibs_dev_del(struct dibs_dev *dibs)
137 {
138 	int i;
139 
140 	mutex_lock(&dibs_dev_list.mutex);
141 	mutex_lock(&clients_lock);
142 	for (i = 0; i < max_client; ++i) {
143 		if (clients[i])
144 			clients[i]->ops->del_dev(dibs);
145 	}
146 	mutex_unlock(&clients_lock);
147 	list_del_init(&dibs->list);
148 	mutex_unlock(&dibs_dev_list.mutex);
149 
150 	device_del(&dibs->dev);
151 }
152 EXPORT_SYMBOL_GPL(dibs_dev_del);
153 
154 static int __init dibs_init(void)
155 {
156 	int rc;
157 
158 	memset(clients, 0, sizeof(clients));
159 	max_client = 0;
160 
161 	rc = dibs_loopback_init();
162 	if (rc)
163 		pr_err("%s fails with %d\n", __func__, rc);
164 
165 	return rc;
166 }
167 
168 static void __exit dibs_exit(void)
169 {
170 	dibs_loopback_exit();
171 }
172 
173 module_init(dibs_init);
174 module_exit(dibs_exit);
175