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 18*cb990a45SAlexandra Winter #include "dibs_loopback.h" 19*cb990a45SAlexandra 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 { 39d324a2caSAlexandra Winter int i, rc = -ENOSPC; 40d324a2caSAlexandra Winter 41d324a2caSAlexandra Winter mutex_lock(&clients_lock); 42d324a2caSAlexandra Winter for (i = 0; i < MAX_DIBS_CLIENTS; ++i) { 43d324a2caSAlexandra Winter if (!clients[i]) { 44d324a2caSAlexandra Winter clients[i] = client; 45d324a2caSAlexandra Winter client->id = i; 46d324a2caSAlexandra Winter if (i == max_client) 47d324a2caSAlexandra Winter max_client++; 48d324a2caSAlexandra Winter rc = 0; 49d324a2caSAlexandra Winter break; 50d324a2caSAlexandra Winter } 51d324a2caSAlexandra Winter } 52d324a2caSAlexandra Winter mutex_unlock(&clients_lock); 53d324a2caSAlexandra Winter 54d324a2caSAlexandra Winter return rc; 55d324a2caSAlexandra Winter } 56d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_register_client); 57d324a2caSAlexandra Winter 58d324a2caSAlexandra Winter int dibs_unregister_client(struct dibs_client *client) 59d324a2caSAlexandra Winter { 60d324a2caSAlexandra Winter int rc = 0; 61d324a2caSAlexandra Winter 62d324a2caSAlexandra Winter mutex_lock(&clients_lock); 63d324a2caSAlexandra Winter clients[client->id] = NULL; 64d324a2caSAlexandra Winter if (client->id + 1 == max_client) 65d324a2caSAlexandra Winter max_client--; 66d324a2caSAlexandra Winter mutex_unlock(&clients_lock); 67d324a2caSAlexandra Winter return rc; 68d324a2caSAlexandra Winter } 69d324a2caSAlexandra Winter EXPORT_SYMBOL_GPL(dibs_unregister_client); 7035758b00SAlexandra Winter 7126972696SAlexandra Winter struct dibs_dev *dibs_dev_alloc(void) 7226972696SAlexandra Winter { 7326972696SAlexandra Winter struct dibs_dev *dibs; 7426972696SAlexandra Winter 7526972696SAlexandra Winter dibs = kzalloc(sizeof(*dibs), GFP_KERNEL); 7626972696SAlexandra Winter 7726972696SAlexandra Winter return dibs; 7826972696SAlexandra Winter } 7926972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_alloc); 8026972696SAlexandra Winter 8126972696SAlexandra Winter int dibs_dev_add(struct dibs_dev *dibs) 8226972696SAlexandra Winter { 8326972696SAlexandra Winter mutex_lock(&dibs_dev_list.mutex); 8426972696SAlexandra Winter list_add(&dibs->list, &dibs_dev_list.list); 8526972696SAlexandra Winter mutex_unlock(&dibs_dev_list.mutex); 8626972696SAlexandra Winter 8726972696SAlexandra Winter return 0; 8826972696SAlexandra Winter } 8926972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_add); 9026972696SAlexandra Winter 9126972696SAlexandra Winter void dibs_dev_del(struct dibs_dev *dibs) 9226972696SAlexandra Winter { 9326972696SAlexandra Winter mutex_lock(&dibs_dev_list.mutex); 9426972696SAlexandra Winter list_del_init(&dibs->list); 9526972696SAlexandra Winter mutex_unlock(&dibs_dev_list.mutex); 9626972696SAlexandra Winter } 9726972696SAlexandra Winter EXPORT_SYMBOL_GPL(dibs_dev_del); 9826972696SAlexandra Winter 9935758b00SAlexandra Winter static int __init dibs_init(void) 10035758b00SAlexandra Winter { 101*cb990a45SAlexandra Winter int rc; 102*cb990a45SAlexandra Winter 10335758b00SAlexandra Winter memset(clients, 0, sizeof(clients)); 10435758b00SAlexandra Winter max_client = 0; 10535758b00SAlexandra Winter 106*cb990a45SAlexandra Winter rc = dibs_loopback_init(); 107*cb990a45SAlexandra Winter if (rc) 108*cb990a45SAlexandra Winter pr_err("%s fails with %d\n", __func__, rc); 109*cb990a45SAlexandra Winter 110*cb990a45SAlexandra Winter return rc; 11135758b00SAlexandra Winter } 11235758b00SAlexandra Winter 11335758b00SAlexandra Winter static void __exit dibs_exit(void) 11435758b00SAlexandra Winter { 115*cb990a45SAlexandra Winter dibs_loopback_exit(); 11635758b00SAlexandra Winter } 11735758b00SAlexandra Winter 11835758b00SAlexandra Winter module_init(dibs_init); 11935758b00SAlexandra Winter module_exit(dibs_exit); 120