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