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 */ 18 static struct attribute *devices_attr[] = { 19 NULL, 20 }; 21 22 static const struct attribute_group devices_attr_group = { 23 .name = "devices", 24 .attrs = devices_attr, 25 }; 26 27 static const struct attribute_group *dev_groups[] = { 28 &devices_attr_group, 29 NULL, 30 }; 31 32 static void release_device(struct device *dev) 33 { 34 kfree(dev); 35 } 36 37 static struct class iommu_class = { 38 .name = "iommu", 39 .dev_release = release_device, 40 .dev_groups = dev_groups, 41 }; 42 43 static int __init iommu_dev_init(void) 44 { 45 return class_register(&iommu_class); 46 } 47 postcore_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 */ 54 int 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 86 error: 87 put_device(iommu->dev); 88 return ret; 89 } 90 EXPORT_SYMBOL_GPL(iommu_device_sysfs_add); 91 92 void 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 } 98 EXPORT_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 */ 106 int 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 } 125 EXPORT_SYMBOL_GPL(iommu_device_link); 126 127 void 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 } 135 EXPORT_SYMBOL_GPL(iommu_device_unlink); 136