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