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(objp: 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(class: &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(size: sizeof(*iommu->dev), GFP_KERNEL); |
63 | if (!iommu->dev) |
64 | return -ENOMEM; |
65 | |
66 | device_initialize(dev: 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(kobj: &iommu->dev->kobj, fmt, vargs); |
74 | va_end(vargs); |
75 | if (ret) |
76 | goto error; |
77 | |
78 | ret = device_add(dev: iommu->dev); |
79 | if (ret) |
80 | goto error; |
81 | |
82 | dev_set_drvdata(dev: iommu->dev, data: iommu); |
83 | |
84 | return 0; |
85 | |
86 | error: |
87 | put_device(dev: 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(dev: iommu->dev, NULL); |
95 | device_unregister(dev: 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 | ret = sysfs_add_link_to_group(kobj: &iommu->dev->kobj, group_name: "devices" , |
111 | target: &link->kobj, link_name: dev_name(dev: link)); |
112 | if (ret) |
113 | return ret; |
114 | |
115 | ret = sysfs_create_link_nowarn(kobj: &link->kobj, target: &iommu->dev->kobj, name: "iommu" ); |
116 | if (ret) |
117 | sysfs_remove_link_from_group(kobj: &iommu->dev->kobj, group_name: "devices" , |
118 | link_name: dev_name(dev: link)); |
119 | |
120 | return ret; |
121 | } |
122 | |
123 | void iommu_device_unlink(struct iommu_device *iommu, struct device *link) |
124 | { |
125 | sysfs_remove_link(kobj: &link->kobj, name: "iommu" ); |
126 | sysfs_remove_link_from_group(kobj: &iommu->dev->kobj, group_name: "devices" , link_name: dev_name(dev: link)); |
127 | } |
128 | |