1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c61959ecSAlex Williamson /*
3c61959ecSAlex Williamson * IOMMU sysfs class support
4c61959ecSAlex Williamson *
5c61959ecSAlex Williamson * Copyright (C) 2014 Red Hat, Inc. All rights reserved.
6c61959ecSAlex Williamson * Author: Alex Williamson <alex.williamson@redhat.com>
7c61959ecSAlex Williamson */
8c61959ecSAlex Williamson
9c61959ecSAlex Williamson #include <linux/device.h>
10c61959ecSAlex Williamson #include <linux/iommu.h>
11c1af7b40SPaul Gortmaker #include <linux/init.h>
12ffd78f00SJoerg Roedel #include <linux/slab.h>
13c61959ecSAlex Williamson
14c61959ecSAlex Williamson /*
15c61959ecSAlex Williamson * We provide a common class "devices" group which initially has no attributes.
16c61959ecSAlex Williamson * As devices are added to the IOMMU, we'll add links to the group.
17c61959ecSAlex Williamson */
18c61959ecSAlex Williamson static struct attribute *devices_attr[] = {
19c61959ecSAlex Williamson NULL,
20c61959ecSAlex Williamson };
21c61959ecSAlex Williamson
226954cf9bSJoerg Roedel static const struct attribute_group devices_attr_group = {
23c61959ecSAlex Williamson .name = "devices",
24c61959ecSAlex Williamson .attrs = devices_attr,
25c61959ecSAlex Williamson };
26c61959ecSAlex Williamson
276954cf9bSJoerg Roedel static const struct attribute_group *dev_groups[] = {
286954cf9bSJoerg Roedel &devices_attr_group,
29c61959ecSAlex Williamson NULL,
30c61959ecSAlex Williamson };
31c61959ecSAlex Williamson
release_device(struct device * dev)326954cf9bSJoerg Roedel static void release_device(struct device *dev)
33c61959ecSAlex Williamson {
34c61959ecSAlex Williamson kfree(dev);
35c61959ecSAlex Williamson }
36c61959ecSAlex Williamson
37c61959ecSAlex Williamson static struct class iommu_class = {
38c61959ecSAlex Williamson .name = "iommu",
396954cf9bSJoerg Roedel .dev_release = release_device,
406954cf9bSJoerg Roedel .dev_groups = dev_groups,
41c61959ecSAlex Williamson };
42c61959ecSAlex Williamson
iommu_dev_init(void)43c61959ecSAlex Williamson static int __init iommu_dev_init(void)
44c61959ecSAlex Williamson {
45c61959ecSAlex Williamson return class_register(&iommu_class);
46c61959ecSAlex Williamson }
47c61959ecSAlex Williamson postcore_initcall(iommu_dev_init);
48c61959ecSAlex Williamson
49c61959ecSAlex Williamson /*
5039ab9555SJoerg Roedel * Init the struct device for the IOMMU. IOMMU specific attributes can
5139ab9555SJoerg Roedel * be provided as an attribute group, allowing a unique namespace per
5239ab9555SJoerg Roedel * IOMMU type.
53c61959ecSAlex Williamson */
iommu_device_sysfs_add(struct iommu_device * iommu,struct device * parent,const struct attribute_group ** groups,const char * fmt,...)5439ab9555SJoerg Roedel int iommu_device_sysfs_add(struct iommu_device *iommu,
5539ab9555SJoerg Roedel struct device *parent,
56c61959ecSAlex Williamson const struct attribute_group **groups,
57c61959ecSAlex Williamson const char *fmt, ...)
58c61959ecSAlex Williamson {
59c61959ecSAlex Williamson va_list vargs;
60c61959ecSAlex Williamson int ret;
61c61959ecSAlex Williamson
622926a2aaSJoerg Roedel iommu->dev = kzalloc(sizeof(*iommu->dev), GFP_KERNEL);
632926a2aaSJoerg Roedel if (!iommu->dev)
642926a2aaSJoerg Roedel return -ENOMEM;
65c61959ecSAlex Williamson
662926a2aaSJoerg Roedel device_initialize(iommu->dev);
672926a2aaSJoerg Roedel
682926a2aaSJoerg Roedel iommu->dev->class = &iommu_class;
692926a2aaSJoerg Roedel iommu->dev->parent = parent;
702926a2aaSJoerg Roedel iommu->dev->groups = groups;
71c61959ecSAlex Williamson
72c61959ecSAlex Williamson va_start(vargs, fmt);
732926a2aaSJoerg Roedel ret = kobject_set_name_vargs(&iommu->dev->kobj, fmt, vargs);
74c61959ecSAlex Williamson va_end(vargs);
75c61959ecSAlex Williamson if (ret)
76c61959ecSAlex Williamson goto error;
77c61959ecSAlex Williamson
782926a2aaSJoerg Roedel ret = device_add(iommu->dev);
79c61959ecSAlex Williamson if (ret)
80c61959ecSAlex Williamson goto error;
81c61959ecSAlex Williamson
822926a2aaSJoerg Roedel dev_set_drvdata(iommu->dev, iommu);
832926a2aaSJoerg Roedel
8439ab9555SJoerg Roedel return 0;
85c61959ecSAlex Williamson
86c61959ecSAlex Williamson error:
872926a2aaSJoerg Roedel put_device(iommu->dev);
8839ab9555SJoerg Roedel return ret;
89c61959ecSAlex Williamson }
90a7ba5c3dSWill Deacon EXPORT_SYMBOL_GPL(iommu_device_sysfs_add);
91c61959ecSAlex Williamson
iommu_device_sysfs_remove(struct iommu_device * iommu)9239ab9555SJoerg Roedel void iommu_device_sysfs_remove(struct iommu_device *iommu)
93c61959ecSAlex Williamson {
942926a2aaSJoerg Roedel dev_set_drvdata(iommu->dev, NULL);
952926a2aaSJoerg Roedel device_unregister(iommu->dev);
962926a2aaSJoerg Roedel iommu->dev = NULL;
97c61959ecSAlex Williamson }
98a7ba5c3dSWill Deacon EXPORT_SYMBOL_GPL(iommu_device_sysfs_remove);
99a7ba5c3dSWill Deacon
100c61959ecSAlex Williamson /*
101c61959ecSAlex Williamson * IOMMU drivers can indicate a device is managed by a given IOMMU using
102c61959ecSAlex Williamson * this interface. A link to the device will be created in the "devices"
103c61959ecSAlex Williamson * directory of the IOMMU device in sysfs and an "iommu" link will be
104c61959ecSAlex Williamson * created under the linked device, pointing back at the IOMMU device.
105c61959ecSAlex Williamson */
iommu_device_link(struct iommu_device * iommu,struct device * link)106e3d10af1SJoerg Roedel int iommu_device_link(struct iommu_device *iommu, struct device *link)
107c61959ecSAlex Williamson {
108c61959ecSAlex Williamson int ret;
109c61959ecSAlex Williamson
1102926a2aaSJoerg Roedel ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices",
111c61959ecSAlex Williamson &link->kobj, dev_name(link));
112c61959ecSAlex Williamson if (ret)
113c61959ecSAlex Williamson return ret;
114c61959ecSAlex Williamson
1152926a2aaSJoerg Roedel ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu");
116c61959ecSAlex Williamson if (ret)
1172926a2aaSJoerg Roedel sysfs_remove_link_from_group(&iommu->dev->kobj, "devices",
118c61959ecSAlex Williamson dev_name(link));
119c61959ecSAlex Williamson
120c61959ecSAlex Williamson return ret;
121c61959ecSAlex Williamson }
122c61959ecSAlex Williamson
iommu_device_unlink(struct iommu_device * iommu,struct device * link)123e3d10af1SJoerg Roedel void iommu_device_unlink(struct iommu_device *iommu, struct device *link)
124c61959ecSAlex Williamson {
125c61959ecSAlex Williamson sysfs_remove_link(&link->kobj, "iommu");
1262926a2aaSJoerg Roedel sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link));
127c61959ecSAlex Williamson }
128