iommu-sysfs.c (3153B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * IOMMU sysfs class support 4 * 5 * Copyright (C) 2014 Red Hat, Inc. All rights reserved. 6 * Author: Alex Williamson <alex.williamson@redhat.com> 7 */ 8 9#include <linux/device.h> 10#include <linux/iommu.h> 11#include <linux/init.h> 12#include <linux/slab.h> 13 14/* 15 * We provide a common class "devices" group which initially has no attributes. 16 * As devices are added to the IOMMU, we'll add links to the group. 17 */ 18static struct attribute *devices_attr[] = { 19 NULL, 20}; 21 22static const struct attribute_group devices_attr_group = { 23 .name = "devices", 24 .attrs = devices_attr, 25}; 26 27static const struct attribute_group *dev_groups[] = { 28 &devices_attr_group, 29 NULL, 30}; 31 32static void release_device(struct device *dev) 33{ 34 kfree(dev); 35} 36 37static struct class iommu_class = { 38 .name = "iommu", 39 .dev_release = release_device, 40 .dev_groups = dev_groups, 41}; 42 43static int __init iommu_dev_init(void) 44{ 45 return class_register(&iommu_class); 46} 47postcore_initcall(iommu_dev_init); 48 49/* 50 * Init the struct device for the IOMMU. IOMMU specific attributes can 51 * be provided as an attribute group, allowing a unique namespace per 52 * IOMMU type. 53 */ 54int iommu_device_sysfs_add(struct iommu_device *iommu, 55 struct device *parent, 56 const struct attribute_group **groups, 57 const char *fmt, ...) 58{ 59 va_list vargs; 60 int ret; 61 62 iommu->dev = kzalloc(sizeof(*iommu->dev), GFP_KERNEL); 63 if (!iommu->dev) 64 return -ENOMEM; 65 66 device_initialize(iommu->dev); 67 68 iommu->dev->class = &iommu_class; 69 iommu->dev->parent = parent; 70 iommu->dev->groups = groups; 71 72 va_start(vargs, fmt); 73 ret = kobject_set_name_vargs(&iommu->dev->kobj, fmt, vargs); 74 va_end(vargs); 75 if (ret) 76 goto error; 77 78 ret = device_add(iommu->dev); 79 if (ret) 80 goto error; 81 82 dev_set_drvdata(iommu->dev, iommu); 83 84 return 0; 85 86error: 87 put_device(iommu->dev); 88 return ret; 89} 90EXPORT_SYMBOL_GPL(iommu_device_sysfs_add); 91 92void iommu_device_sysfs_remove(struct iommu_device *iommu) 93{ 94 dev_set_drvdata(iommu->dev, NULL); 95 device_unregister(iommu->dev); 96 iommu->dev = NULL; 97} 98EXPORT_SYMBOL_GPL(iommu_device_sysfs_remove); 99 100/* 101 * IOMMU drivers can indicate a device is managed by a given IOMMU using 102 * this interface. A link to the device will be created in the "devices" 103 * directory of the IOMMU device in sysfs and an "iommu" link will be 104 * created under the linked device, pointing back at the IOMMU device. 105 */ 106int iommu_device_link(struct iommu_device *iommu, struct device *link) 107{ 108 int ret; 109 110 if (!iommu || IS_ERR(iommu)) 111 return -ENODEV; 112 113 ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices", 114 &link->kobj, dev_name(link)); 115 if (ret) 116 return ret; 117 118 ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu"); 119 if (ret) 120 sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", 121 dev_name(link)); 122 123 return ret; 124} 125EXPORT_SYMBOL_GPL(iommu_device_link); 126 127void iommu_device_unlink(struct iommu_device *iommu, struct device *link) 128{ 129 if (!iommu || IS_ERR(iommu)) 130 return; 131 132 sysfs_remove_link(&link->kobj, "iommu"); 133 sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link)); 134} 135EXPORT_SYMBOL_GPL(iommu_device_unlink);