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