// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2024 , NVIDIA CORPORATION & AFFILIATES
*/
#include <linux/auxiliary_bus.h>
#include <linux/slab.h>
#define AUXILIARY_MAX_IRQ_NAME 11
struct auxiliary_irq_info {
struct device_attribute sysfs_attr;
char name[AUXILIARY_MAX_IRQ_NAME];
};
static struct attribute *auxiliary_irq_attrs[] = {
NULL
};
static const struct attribute_group auxiliary_irqs_group = {
.name = "irqs" ,
.attrs = auxiliary_irq_attrs,
};
static int auxiliary_irq_dir_prepare(struct auxiliary_device *auxdev)
{
int ret = 0 ;
guard(mutex)(&auxdev->sysfs.lock);
if (auxdev->sysfs.irq_dir_exists)
return 0 ;
ret = devm_device_add_group(&auxdev->dev, &auxiliary_irqs_group);
if (ret)
return ret;
auxdev->sysfs.irq_dir_exists = true ;
xa_init(&auxdev->sysfs.irqs);
return 0 ;
}
/**
* auxiliary_device_sysfs_irq_add - add a sysfs entry for the given IRQ
* @ auxdev : auxiliary bus device to add the sysfs entry .
* @ irq : The associated interrupt number .
*
* This function should be called after auxiliary device have successfully
* received the irq .
* The driver is responsible to add a unique irq for the auxiliary device . The
* driver can invoke this function from multiple thread context safely for
* unique irqs of the auxiliary devices . The driver must not invoke this API
* multiple times if the irq is already added previously .
*
* Return : zero on success or an error code on failure .
*/
int auxiliary_device_sysfs_irq_add(struct auxiliary_device *auxdev, int irq)
{
struct auxiliary_irq_info *info __free(kfree) = NULL;
struct device *dev = &auxdev->dev;
int ret;
ret = auxiliary_irq_dir_prepare(auxdev);
if (ret)
return ret;
info = kzalloc(sizeof (*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
sysfs_attr_init(&info->sysfs_attr.attr);
snprintf(info->name, AUXILIARY_MAX_IRQ_NAME, "%d" , irq);
ret = xa_insert(&auxdev->sysfs.irqs, irq, info, GFP_KERNEL);
if (ret)
return ret;
info->sysfs_attr.attr.name = info->name;
ret = sysfs_add_file_to_group(&dev->kobj, &info->sysfs_attr.attr,
auxiliary_irqs_group.name);
if (ret)
goto sysfs_add_err;
xa_store(&auxdev->sysfs.irqs, irq, no_free_ptr(info), GFP_KERNEL);
return 0 ;
sysfs_add_err:
xa_erase(&auxdev->sysfs.irqs, irq);
return ret;
}
EXPORT_SYMBOL_GPL(auxiliary_device_sysfs_irq_add);
/**
* auxiliary_device_sysfs_irq_remove - remove a sysfs entry for the given IRQ
* @ auxdev : auxiliary bus device to add the sysfs entry .
* @ irq : the IRQ to remove .
*
* This function should be called to remove an IRQ sysfs entry .
* The driver must invoke this API when IRQ is released by the device .
*/
void auxiliary_device_sysfs_irq_remove(struct auxiliary_device *auxdev, int irq)
{
struct auxiliary_irq_info *info __free(kfree) = xa_load(&auxdev->sysfs.irqs, irq);
struct device *dev = &auxdev->dev;
if (!info) {
dev_err(&auxdev->dev, "IRQ %d doesn't exist\n" , irq);
return ;
}
sysfs_remove_file_from_group(&dev->kobj, &info->sysfs_attr.attr,
auxiliary_irqs_group.name);
xa_erase(&auxdev->sysfs.irqs, irq);
}
EXPORT_SYMBOL_GPL(auxiliary_device_sysfs_irq_remove);
Messung V0.5 in Prozent C=97 H=96 G=96
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland