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 91 void iommu_device_sysfs_remove(struct iommu_device *iommu) 92 { 93 dev_set_drvdata(iommu->dev, NULL); 94 device_unregister(iommu->dev); 95 iommu->dev = NULL; 96 } 97 /* 98 * IOMMU drivers can indicate a device is managed by a given IOMMU using 99 * this interface. A link to the device will be created in the "devices" 100 * directory of the IOMMU device in sysfs and an "iommu" link will be 101 * created under the linked device, pointing back at the IOMMU device. 102 */ 103 int iommu_device_link(struct iommu_device *iommu, struct device *link) 104 { 105 int ret; 106 107 if (!iommu || IS_ERR(iommu)) 108 return -ENODEV; 109 110 ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices", 111 &link->kobj, dev_name(link)); 112 if (ret) 113 return ret; 114 115 ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu"); 116 if (ret) 117 sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", 118 dev_name(link)); 119 120 return ret; 121 } 122 123 void iommu_device_unlink(struct iommu_device *iommu, struct device *link) 124 { 125 if (!iommu || IS_ERR(iommu)) 126 return; 127 128 sysfs_remove_link(&link->kobj, "iommu"); 129 sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link)); 130 } 131