linux/drivers/dibs/dibs_main.c
Linus Torvalds bf4afc53b7 Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
This was done entirely with mindless brute force, using

    git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
        xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'

to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.

Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.

For the same reason the 'flex' versions will be done as a separate
conversion.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 17:09:51 -08:00

274 lines
6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* DIBS - Direct Internal Buffer Sharing
*
* Implementation of the DIBS class module
*
* Copyright IBM Corp. 2025
*/
#define pr_fmt(fmt) "dibs: " fmt
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/dibs.h>
#include "dibs_loopback.h"
MODULE_DESCRIPTION("Direct Internal Buffer Sharing class");
MODULE_LICENSE("GPL");
static struct class *dibs_class;
/* use an array rather a list for fast mapping: */
static struct dibs_client *clients[MAX_DIBS_CLIENTS];
static u8 max_client;
static DEFINE_MUTEX(clients_lock);
struct dibs_dev_list {
struct list_head list;
struct mutex mutex; /* protects dibs device list */
};
static struct dibs_dev_list dibs_dev_list = {
.list = LIST_HEAD_INIT(dibs_dev_list.list),
.mutex = __MUTEX_INITIALIZER(dibs_dev_list.mutex),
};
static void dibs_setup_forwarding(struct dibs_client *client,
struct dibs_dev *dibs)
{
unsigned long flags;
spin_lock_irqsave(&dibs->lock, flags);
dibs->subs[client->id] = client;
spin_unlock_irqrestore(&dibs->lock, flags);
}
int dibs_register_client(struct dibs_client *client)
{
struct dibs_dev *dibs;
int i, rc = -ENOSPC;
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
if (!clients[i]) {
clients[i] = client;
client->id = i;
if (i == max_client)
max_client++;
rc = 0;
break;
}
}
mutex_unlock(&clients_lock);
if (i < MAX_DIBS_CLIENTS) {
/* initialize with all devices that we got so far */
list_for_each_entry(dibs, &dibs_dev_list.list, list) {
dibs->priv[i] = NULL;
client->ops->add_dev(dibs);
dibs_setup_forwarding(client, dibs);
}
}
mutex_unlock(&dibs_dev_list.mutex);
return rc;
}
EXPORT_SYMBOL_GPL(dibs_register_client);
int dibs_unregister_client(struct dibs_client *client)
{
struct dibs_dev *dibs;
unsigned long flags;
int max_dmbs;
int rc = 0;
mutex_lock(&dibs_dev_list.mutex);
list_for_each_entry(dibs, &dibs_dev_list.list, list) {
spin_lock_irqsave(&dibs->lock, flags);
max_dmbs = dibs->ops->max_dmbs();
for (int i = 0; i < max_dmbs; ++i) {
if (dibs->dmb_clientid_arr[i] == client->id) {
WARN(1, "%s: attempt to unregister '%s' with registered dmb(s)\n",
__func__, client->name);
rc = -EBUSY;
goto err_reg_dmb;
}
}
/* Stop forwarding IRQs and events */
dibs->subs[client->id] = NULL;
spin_unlock_irqrestore(&dibs->lock, flags);
clients[client->id]->ops->del_dev(dibs);
dibs->priv[client->id] = NULL;
}
mutex_lock(&clients_lock);
clients[client->id] = NULL;
if (client->id + 1 == max_client)
max_client--;
mutex_unlock(&clients_lock);
mutex_unlock(&dibs_dev_list.mutex);
return rc;
err_reg_dmb:
spin_unlock_irqrestore(&dibs->lock, flags);
mutex_unlock(&dibs_dev_list.mutex);
return rc;
}
EXPORT_SYMBOL_GPL(dibs_unregister_client);
static void dibs_dev_release(struct device *dev)
{
struct dibs_dev *dibs;
dibs = container_of(dev, struct dibs_dev, dev);
kfree(dibs);
}
struct dibs_dev *dibs_dev_alloc(void)
{
struct dibs_dev *dibs;
dibs = kzalloc_obj(*dibs);
if (!dibs)
return dibs;
dibs->dev.release = dibs_dev_release;
dibs->dev.class = dibs_class;
device_initialize(&dibs->dev);
return dibs;
}
EXPORT_SYMBOL_GPL(dibs_dev_alloc);
static ssize_t gid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dibs_dev *dibs;
dibs = container_of(dev, struct dibs_dev, dev);
return sysfs_emit(buf, "%pUb\n", &dibs->gid);
}
static DEVICE_ATTR_RO(gid);
static ssize_t fabric_id_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dibs_dev *dibs;
u16 fabric_id;
dibs = container_of(dev, struct dibs_dev, dev);
fabric_id = dibs->ops->get_fabric_id(dibs);
return sysfs_emit(buf, "0x%04x\n", fabric_id);
}
static DEVICE_ATTR_RO(fabric_id);
static struct attribute *dibs_dev_attrs[] = {
&dev_attr_gid.attr,
&dev_attr_fabric_id.attr,
NULL,
};
static const struct attribute_group dibs_dev_attr_group = {
.attrs = dibs_dev_attrs,
};
int dibs_dev_add(struct dibs_dev *dibs)
{
int max_dmbs;
int i, ret;
max_dmbs = dibs->ops->max_dmbs();
spin_lock_init(&dibs->lock);
dibs->dmb_clientid_arr = kzalloc(max_dmbs, GFP_KERNEL);
if (!dibs->dmb_clientid_arr)
return -ENOMEM;
memset(dibs->dmb_clientid_arr, NO_DIBS_CLIENT, max_dmbs);
ret = device_add(&dibs->dev);
if (ret)
goto free_client_arr;
ret = sysfs_create_group(&dibs->dev.kobj, &dibs_dev_attr_group);
if (ret) {
dev_err(&dibs->dev, "sysfs_create_group failed for dibs_dev\n");
goto err_device_del;
}
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < max_client; ++i) {
if (clients[i]) {
clients[i]->ops->add_dev(dibs);
dibs_setup_forwarding(clients[i], dibs);
}
}
mutex_unlock(&clients_lock);
list_add(&dibs->list, &dibs_dev_list.list);
mutex_unlock(&dibs_dev_list.mutex);
return 0;
err_device_del:
device_del(&dibs->dev);
free_client_arr:
kfree(dibs->dmb_clientid_arr);
return ret;
}
EXPORT_SYMBOL_GPL(dibs_dev_add);
void dibs_dev_del(struct dibs_dev *dibs)
{
unsigned long flags;
int i;
sysfs_remove_group(&dibs->dev.kobj, &dibs_dev_attr_group);
spin_lock_irqsave(&dibs->lock, flags);
for (i = 0; i < MAX_DIBS_CLIENTS; ++i)
dibs->subs[i] = NULL;
spin_unlock_irqrestore(&dibs->lock, flags);
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < max_client; ++i) {
if (clients[i])
clients[i]->ops->del_dev(dibs);
}
mutex_unlock(&clients_lock);
list_del_init(&dibs->list);
mutex_unlock(&dibs_dev_list.mutex);
device_del(&dibs->dev);
kfree(dibs->dmb_clientid_arr);
}
EXPORT_SYMBOL_GPL(dibs_dev_del);
static int __init dibs_init(void)
{
int rc;
dibs_class = class_create("dibs");
if (IS_ERR(dibs_class))
return PTR_ERR(dibs_class);
rc = dibs_loopback_init();
if (rc)
pr_err("%s fails with %d\n", __func__, rc);
return rc;
}
static void __exit dibs_exit(void)
{
dibs_loopback_exit();
class_destroy(dibs_class);
}
subsys_initcall(dibs_init);
module_exit(dibs_exit);