xref: /linux/drivers/dibs/dibs_main.c (revision 05e68d8dedf34f270cc3769ffe7f0ed413f23add)
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 
2380473734SJulian Ruess static struct class *dibs_class;
2480473734SJulian Ruess 
2535758b00SAlexandra Winter /* use an array rather a list for fast mapping: */
2635758b00SAlexandra Winter static struct dibs_client *clients[MAX_DIBS_CLIENTS];
2735758b00SAlexandra Winter static u8 max_client;
28d324a2caSAlexandra Winter static DEFINE_MUTEX(clients_lock);
2926972696SAlexandra Winter struct dibs_dev_list {
3026972696SAlexandra Winter 	struct list_head list;
3126972696SAlexandra Winter 	struct mutex mutex; /* protects dibs device list */
3226972696SAlexandra Winter };
3326972696SAlexandra Winter 
3426972696SAlexandra Winter static struct dibs_dev_list dibs_dev_list = {
3526972696SAlexandra Winter 	.list = LIST_HEAD_INIT(dibs_dev_list.list),
3626972696SAlexandra Winter 	.mutex = __MUTEX_INITIALIZER(dibs_dev_list.mutex),
3726972696SAlexandra Winter };
38d324a2caSAlexandra Winter 
39d324a2caSAlexandra Winter int dibs_register_client(struct dibs_client *client)
40d324a2caSAlexandra Winter {
4169baaac9SAlexandra Winter 	struct dibs_dev *dibs;
42d324a2caSAlexandra Winter 	int i, rc = -ENOSPC;
43d324a2caSAlexandra Winter 
4469baaac9SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
45d324a2caSAlexandra Winter 	mutex_lock(&clients_lock);
46d324a2caSAlexandra Winter 	for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
47d324a2caSAlexandra Winter 		if (!clients[i]) {
48d324a2caSAlexandra Winter 			clients[i] = client;
49d324a2caSAlexandra Winter 			client->id = i;
50d324a2caSAlexandra Winter 			if (i == max_client)
51d324a2caSAlexandra Winter 				max_client++;
52d324a2caSAlexandra Winter 			rc = 0;
53d324a2caSAlexandra Winter 			break;
54d324a2caSAlexandra Winter 		}
55d324a2caSAlexandra Winter 	}
56d324a2caSAlexandra Winter 	mutex_unlock(&clients_lock);
57d324a2caSAlexandra Winter 
5869baaac9SAlexandra Winter 	if (i < MAX_DIBS_CLIENTS) {
5969baaac9SAlexandra Winter 		/* initialize with all devices that we got so far */
6069baaac9SAlexandra Winter 		list_for_each_entry(dibs, &dibs_dev_list.list, list) {
6169baaac9SAlexandra Winter 			dibs->priv[i] = NULL;
6269baaac9SAlexandra Winter 			client->ops->add_dev(dibs);
6369baaac9SAlexandra Winter 		}
6469baaac9SAlexandra Winter 	}
6569baaac9SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
6669baaac9SAlexandra Winter 
67d324a2caSAlexandra Winter 	return rc;
68d324a2caSAlexandra Winter }
69d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_register_client);
70d324a2caSAlexandra Winter 
71d324a2caSAlexandra Winter int dibs_unregister_client(struct dibs_client *client)
72d324a2caSAlexandra Winter {
7369baaac9SAlexandra Winter 	struct dibs_dev *dibs;
74d324a2caSAlexandra Winter 	int rc = 0;
75d324a2caSAlexandra Winter 
7669baaac9SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
7769baaac9SAlexandra Winter 	list_for_each_entry(dibs, &dibs_dev_list.list, list) {
7869baaac9SAlexandra Winter 		clients[client->id]->ops->del_dev(dibs);
7969baaac9SAlexandra Winter 		dibs->priv[client->id] = NULL;
8069baaac9SAlexandra Winter 	}
8169baaac9SAlexandra Winter 
82d324a2caSAlexandra Winter 	mutex_lock(&clients_lock);
83d324a2caSAlexandra Winter 	clients[client->id] = NULL;
84d324a2caSAlexandra Winter 	if (client->id + 1 == max_client)
85d324a2caSAlexandra Winter 		max_client--;
86d324a2caSAlexandra Winter 	mutex_unlock(&clients_lock);
8769baaac9SAlexandra Winter 
8869baaac9SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
89d324a2caSAlexandra Winter 	return rc;
90d324a2caSAlexandra Winter }
91d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_unregister_client);
9235758b00SAlexandra Winter 
93845c334aSJulian Ruess static void dibs_dev_release(struct device *dev)
94845c334aSJulian Ruess {
95845c334aSJulian Ruess 	struct dibs_dev *dibs;
96845c334aSJulian Ruess 
97845c334aSJulian Ruess 	dibs = container_of(dev, struct dibs_dev, dev);
98845c334aSJulian Ruess 
99845c334aSJulian Ruess 	kfree(dibs);
100845c334aSJulian Ruess }
101845c334aSJulian Ruess 
10226972696SAlexandra Winter struct dibs_dev *dibs_dev_alloc(void)
10326972696SAlexandra Winter {
10426972696SAlexandra Winter 	struct dibs_dev *dibs;
10526972696SAlexandra Winter 
10626972696SAlexandra Winter 	dibs = kzalloc(sizeof(*dibs), GFP_KERNEL);
107845c334aSJulian Ruess 	if (!dibs)
108845c334aSJulian Ruess 		return dibs;
109845c334aSJulian Ruess 	dibs->dev.release = dibs_dev_release;
11080473734SJulian Ruess 	dibs->dev.class = dibs_class;
111845c334aSJulian Ruess 	device_initialize(&dibs->dev);
11226972696SAlexandra Winter 
11326972696SAlexandra Winter 	return dibs;
11426972696SAlexandra Winter }
11526972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_alloc);
11626972696SAlexandra Winter 
117*05e68d8dSAlexandra Winter static ssize_t gid_show(struct device *dev, struct device_attribute *attr,
118*05e68d8dSAlexandra Winter 			char *buf)
119*05e68d8dSAlexandra Winter {
120*05e68d8dSAlexandra Winter 	struct dibs_dev *dibs;
121*05e68d8dSAlexandra Winter 
122*05e68d8dSAlexandra Winter 	dibs = container_of(dev, struct dibs_dev, dev);
123*05e68d8dSAlexandra Winter 
124*05e68d8dSAlexandra Winter 	return sysfs_emit(buf, "%pUb\n", &dibs->gid);
125*05e68d8dSAlexandra Winter }
126*05e68d8dSAlexandra Winter static DEVICE_ATTR_RO(gid);
127*05e68d8dSAlexandra Winter 
12880473734SJulian Ruess static ssize_t fabric_id_show(struct device *dev, struct device_attribute *attr,
12980473734SJulian Ruess 			      char *buf)
13080473734SJulian Ruess {
13180473734SJulian Ruess 	struct dibs_dev *dibs;
13280473734SJulian Ruess 	u16 fabric_id;
13380473734SJulian Ruess 
13480473734SJulian Ruess 	dibs = container_of(dev, struct dibs_dev, dev);
13580473734SJulian Ruess 	fabric_id = dibs->ops->get_fabric_id(dibs);
13680473734SJulian Ruess 
13780473734SJulian Ruess 	return sysfs_emit(buf, "0x%04x\n", fabric_id);
13880473734SJulian Ruess }
13980473734SJulian Ruess static DEVICE_ATTR_RO(fabric_id);
14080473734SJulian Ruess 
14180473734SJulian Ruess static struct attribute *dibs_dev_attrs[] = {
142*05e68d8dSAlexandra Winter 	&dev_attr_gid.attr,
14380473734SJulian Ruess 	&dev_attr_fabric_id.attr,
14480473734SJulian Ruess 	NULL,
14580473734SJulian Ruess };
14680473734SJulian Ruess 
14780473734SJulian Ruess static const struct attribute_group dibs_dev_attr_group = {
14880473734SJulian Ruess 	.attrs = dibs_dev_attrs,
14980473734SJulian Ruess };
15080473734SJulian Ruess 
15126972696SAlexandra Winter int dibs_dev_add(struct dibs_dev *dibs)
15226972696SAlexandra Winter {
153845c334aSJulian Ruess 	int i, ret;
154845c334aSJulian Ruess 
155845c334aSJulian Ruess 	ret = device_add(&dibs->dev);
156845c334aSJulian Ruess 	if (ret)
157845c334aSJulian Ruess 		return ret;
15869baaac9SAlexandra Winter 
15980473734SJulian Ruess 	ret = sysfs_create_group(&dibs->dev.kobj, &dibs_dev_attr_group);
16080473734SJulian Ruess 	if (ret) {
16180473734SJulian Ruess 		dev_err(&dibs->dev, "sysfs_create_group failed for dibs_dev\n");
16280473734SJulian Ruess 		goto err_device_del;
16380473734SJulian Ruess 	}
16426972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
16569baaac9SAlexandra Winter 	mutex_lock(&clients_lock);
16669baaac9SAlexandra Winter 	for (i = 0; i < max_client; ++i) {
16769baaac9SAlexandra Winter 		if (clients[i])
16869baaac9SAlexandra Winter 			clients[i]->ops->add_dev(dibs);
16969baaac9SAlexandra Winter 	}
17069baaac9SAlexandra Winter 	mutex_unlock(&clients_lock);
17126972696SAlexandra Winter 	list_add(&dibs->list, &dibs_dev_list.list);
17226972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
17326972696SAlexandra Winter 
17426972696SAlexandra Winter 	return 0;
17580473734SJulian Ruess 
17680473734SJulian Ruess err_device_del:
17780473734SJulian Ruess 	device_del(&dibs->dev);
17880473734SJulian Ruess 	return ret;
17980473734SJulian Ruess 
18026972696SAlexandra Winter }
18126972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_add);
18226972696SAlexandra Winter 
18326972696SAlexandra Winter void dibs_dev_del(struct dibs_dev *dibs)
18426972696SAlexandra Winter {
18569baaac9SAlexandra Winter 	int i;
18669baaac9SAlexandra Winter 
18726972696SAlexandra Winter 	mutex_lock(&dibs_dev_list.mutex);
18869baaac9SAlexandra Winter 	mutex_lock(&clients_lock);
18969baaac9SAlexandra Winter 	for (i = 0; i < max_client; ++i) {
19069baaac9SAlexandra Winter 		if (clients[i])
19169baaac9SAlexandra Winter 			clients[i]->ops->del_dev(dibs);
19269baaac9SAlexandra Winter 	}
19369baaac9SAlexandra Winter 	mutex_unlock(&clients_lock);
19426972696SAlexandra Winter 	list_del_init(&dibs->list);
19526972696SAlexandra Winter 	mutex_unlock(&dibs_dev_list.mutex);
196845c334aSJulian Ruess 
197845c334aSJulian Ruess 	device_del(&dibs->dev);
19826972696SAlexandra Winter }
19926972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_del);
20026972696SAlexandra Winter 
20135758b00SAlexandra Winter static int __init dibs_init(void)
20235758b00SAlexandra Winter {
203cb990a45SAlexandra Winter 	int rc;
204cb990a45SAlexandra Winter 
20535758b00SAlexandra Winter 	memset(clients, 0, sizeof(clients));
20635758b00SAlexandra Winter 	max_client = 0;
20735758b00SAlexandra Winter 
20880473734SJulian Ruess 	dibs_class = class_create("dibs");
20980473734SJulian Ruess 	if (IS_ERR(&dibs_class))
21080473734SJulian Ruess 		return PTR_ERR(&dibs_class);
21180473734SJulian Ruess 
212cb990a45SAlexandra Winter 	rc = dibs_loopback_init();
213cb990a45SAlexandra Winter 	if (rc)
214cb990a45SAlexandra Winter 		pr_err("%s fails with %d\n", __func__, rc);
215cb990a45SAlexandra Winter 
216cb990a45SAlexandra Winter 	return rc;
21735758b00SAlexandra Winter }
21835758b00SAlexandra Winter 
21935758b00SAlexandra Winter static void __exit dibs_exit(void)
22035758b00SAlexandra Winter {
221cb990a45SAlexandra Winter 	dibs_loopback_exit();
22280473734SJulian Ruess 	class_destroy(dibs_class);
22335758b00SAlexandra Winter }
22435758b00SAlexandra Winter 
22535758b00SAlexandra Winter module_init(dibs_init);
22635758b00SAlexandra Winter module_exit(dibs_exit);
227