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 struct dibs_dev *dibs_dev_alloc(void) 92 { 93 struct dibs_dev *dibs; 94 95 dibs = kzalloc(sizeof(*dibs), GFP_KERNEL); 96 97 return dibs; 98 } 99 EXPORT_SYMBOL_GPL(dibs_dev_alloc); 100 101 int dibs_dev_add(struct dibs_dev *dibs) 102 { 103 int i; 104 105 mutex_lock(&dibs_dev_list.mutex); 106 mutex_lock(&clients_lock); 107 for (i = 0; i < max_client; ++i) { 108 if (clients[i]) 109 clients[i]->ops->add_dev(dibs); 110 } 111 mutex_unlock(&clients_lock); 112 list_add(&dibs->list, &dibs_dev_list.list); 113 mutex_unlock(&dibs_dev_list.mutex); 114 115 return 0; 116 } 117 EXPORT_SYMBOL_GPL(dibs_dev_add); 118 119 void dibs_dev_del(struct dibs_dev *dibs) 120 { 121 int i; 122 123 mutex_lock(&dibs_dev_list.mutex); 124 mutex_lock(&clients_lock); 125 for (i = 0; i < max_client; ++i) { 126 if (clients[i]) 127 clients[i]->ops->del_dev(dibs); 128 } 129 mutex_unlock(&clients_lock); 130 list_del_init(&dibs->list); 131 mutex_unlock(&dibs_dev_list.mutex); 132 } 133 EXPORT_SYMBOL_GPL(dibs_dev_del); 134 135 static int __init dibs_init(void) 136 { 137 int rc; 138 139 memset(clients, 0, sizeof(clients)); 140 max_client = 0; 141 142 rc = dibs_loopback_init(); 143 if (rc) 144 pr_err("%s fails with %d\n", __func__, rc); 145 146 return rc; 147 } 148 149 static void __exit dibs_exit(void) 150 { 151 dibs_loopback_exit(); 152 } 153 154 module_init(dibs_init); 155 module_exit(dibs_exit); 156