Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
c61959ec AW |
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> | |
c61959ec AW |
7 | */ |
8 | ||
9 | #include <linux/device.h> | |
10 | #include <linux/iommu.h> | |
c1af7b40 | 11 | #include <linux/init.h> |
ffd78f00 | 12 | #include <linux/slab.h> |
c61959ec AW |
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 | ||
6954cf9b | 22 | static const struct attribute_group devices_attr_group = { |
c61959ec AW |
23 | .name = "devices", |
24 | .attrs = devices_attr, | |
25 | }; | |
26 | ||
6954cf9b JR |
27 | static const struct attribute_group *dev_groups[] = { |
28 | &devices_attr_group, | |
c61959ec AW |
29 | NULL, |
30 | }; | |
31 | ||
6954cf9b | 32 | static void release_device(struct device *dev) |
c61959ec AW |
33 | { |
34 | kfree(dev); | |
35 | } | |
36 | ||
37 | static struct class iommu_class = { | |
38 | .name = "iommu", | |
6954cf9b JR |
39 | .dev_release = release_device, |
40 | .dev_groups = dev_groups, | |
c61959ec AW |
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 | /* | |
39ab9555 JR |
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. | |
c61959ec | 53 | */ |
39ab9555 JR |
54 | int iommu_device_sysfs_add(struct iommu_device *iommu, |
55 | struct device *parent, | |
56 | const struct attribute_group **groups, | |
57 | const char *fmt, ...) | |
c61959ec | 58 | { |
c61959ec AW |
59 | va_list vargs; |
60 | int ret; | |
61 | ||
2926a2aa JR |
62 | iommu->dev = kzalloc(sizeof(*iommu->dev), GFP_KERNEL); |
63 | if (!iommu->dev) | |
64 | return -ENOMEM; | |
c61959ec | 65 | |
2926a2aa JR |
66 | device_initialize(iommu->dev); |
67 | ||
68 | iommu->dev->class = &iommu_class; | |
69 | iommu->dev->parent = parent; | |
70 | iommu->dev->groups = groups; | |
c61959ec AW |
71 | |
72 | va_start(vargs, fmt); | |
2926a2aa | 73 | ret = kobject_set_name_vargs(&iommu->dev->kobj, fmt, vargs); |
c61959ec AW |
74 | va_end(vargs); |
75 | if (ret) | |
76 | goto error; | |
77 | ||
2926a2aa | 78 | ret = device_add(iommu->dev); |
c61959ec AW |
79 | if (ret) |
80 | goto error; | |
81 | ||
2926a2aa JR |
82 | dev_set_drvdata(iommu->dev, iommu); |
83 | ||
39ab9555 | 84 | return 0; |
c61959ec AW |
85 | |
86 | error: | |
2926a2aa | 87 | put_device(iommu->dev); |
39ab9555 | 88 | return ret; |
c61959ec | 89 | } |
a7ba5c3d | 90 | EXPORT_SYMBOL_GPL(iommu_device_sysfs_add); |
c61959ec | 91 | |
39ab9555 | 92 | void iommu_device_sysfs_remove(struct iommu_device *iommu) |
c61959ec | 93 | { |
2926a2aa JR |
94 | dev_set_drvdata(iommu->dev, NULL); |
95 | device_unregister(iommu->dev); | |
96 | iommu->dev = NULL; | |
c61959ec | 97 | } |
a7ba5c3d WD |
98 | EXPORT_SYMBOL_GPL(iommu_device_sysfs_remove); |
99 | ||
c61959ec AW |
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 | */ | |
e3d10af1 | 106 | int iommu_device_link(struct iommu_device *iommu, struct device *link) |
c61959ec AW |
107 | { |
108 | int ret; | |
109 | ||
e3d10af1 | 110 | if (!iommu || IS_ERR(iommu)) |
c61959ec AW |
111 | return -ENODEV; |
112 | ||
2926a2aa | 113 | ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices", |
c61959ec AW |
114 | &link->kobj, dev_name(link)); |
115 | if (ret) | |
116 | return ret; | |
117 | ||
2926a2aa | 118 | ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu"); |
c61959ec | 119 | if (ret) |
2926a2aa | 120 | sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", |
c61959ec AW |
121 | dev_name(link)); |
122 | ||
123 | return ret; | |
124 | } | |
a7ba5c3d | 125 | EXPORT_SYMBOL_GPL(iommu_device_link); |
c61959ec | 126 | |
e3d10af1 | 127 | void iommu_device_unlink(struct iommu_device *iommu, struct device *link) |
c61959ec | 128 | { |
e3d10af1 | 129 | if (!iommu || IS_ERR(iommu)) |
c61959ec AW |
130 | return; |
131 | ||
132 | sysfs_remove_link(&link->kobj, "iommu"); | |
2926a2aa | 133 | sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link)); |
c61959ec | 134 | } |
a7ba5c3d | 135 | EXPORT_SYMBOL_GPL(iommu_device_unlink); |