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