forked from Minki/linux
iommu: Add sysfs support for IOMMUs
IOMMUs currently have no common representation to userspace, most seem to have no representation at all aside from a few printks on bootup. There are however features of IOMMUs that are useful to know about. For instance the IOMMU might support superpages, making use of processor large/huge pages more important in a device assignment scenario. It's also useful to create cross links between devices and IOMMU hardware units, so that users might be able to load balance their devices to avoid thrashing a single hardware unit. This patch adds a device create and destroy interface as well as device linking, making it very lightweight for an IOMMU driver to add basic support. IOMMU drivers can provide additional attributes automatically by using an attribute_group. The attributes exposed are expected to be relatively device specific, the means to retrieve them certainly are, so there are currently no common attributes for the new class created here. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
fd2852d5da
commit
c61959ecbb
17
Documentation/ABI/testing/sysfs-class-iommu
Normal file
17
Documentation/ABI/testing/sysfs-class-iommu
Normal file
@ -0,0 +1,17 @@
|
||||
What: /sys/class/iommu/<iommu>/devices/
|
||||
Date: June 2014
|
||||
KernelVersion: 3.17
|
||||
Contact: Alex Williamson <alex.williamson@redhat.com>
|
||||
Description:
|
||||
IOMMU drivers are able to link devices managed by a
|
||||
given IOMMU here to allow association of IOMMU to
|
||||
device.
|
||||
|
||||
What: /sys/devices/.../iommu
|
||||
Date: June 2014
|
||||
KernelVersion: 3.17
|
||||
Contact: Alex Williamson <alex.williamson@redhat.com>
|
||||
Description:
|
||||
IOMMU drivers are able to link the IOMMU for a
|
||||
given device here to allow association of device to
|
||||
IOMMU.
|
@ -1,5 +1,6 @@
|
||||
obj-$(CONFIG_IOMMU_API) += iommu.o
|
||||
obj-$(CONFIG_IOMMU_API) += iommu-traces.o
|
||||
obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
|
||||
obj-$(CONFIG_OF_IOMMU) += of_iommu.o
|
||||
obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
|
||||
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
|
||||
|
133
drivers/iommu/iommu-sysfs.c
Normal file
133
drivers/iommu/iommu-sysfs.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* IOMMU sysfs class support
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All rights reserved.
|
||||
* Author: Alex Williamson <alex.williamson@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* We provide a common class "devices" group which initially has no attributes.
|
||||
* As devices are added to the IOMMU, we'll add links to the group.
|
||||
*/
|
||||
static struct attribute *devices_attr[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group iommu_devices_attr_group = {
|
||||
.name = "devices",
|
||||
.attrs = devices_attr,
|
||||
};
|
||||
|
||||
static const struct attribute_group *iommu_dev_groups[] = {
|
||||
&iommu_devices_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void iommu_release_device(struct device *dev)
|
||||
{
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct class iommu_class = {
|
||||
.name = "iommu",
|
||||
.dev_release = iommu_release_device,
|
||||
.dev_groups = iommu_dev_groups,
|
||||
};
|
||||
|
||||
static int __init iommu_dev_init(void)
|
||||
{
|
||||
return class_register(&iommu_class);
|
||||
}
|
||||
postcore_initcall(iommu_dev_init);
|
||||
|
||||
/*
|
||||
* Create an IOMMU device and return a pointer to it. IOMMU specific
|
||||
* attributes can be provided as an attribute group, allowing a unique
|
||||
* namespace per IOMMU type.
|
||||
*/
|
||||
struct device *iommu_device_create(struct device *parent, void *drvdata,
|
||||
const struct attribute_group **groups,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct device *dev;
|
||||
va_list vargs;
|
||||
int ret;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
device_initialize(dev);
|
||||
|
||||
dev->class = &iommu_class;
|
||||
dev->parent = parent;
|
||||
dev->groups = groups;
|
||||
dev_set_drvdata(dev, drvdata);
|
||||
|
||||
va_start(vargs, fmt);
|
||||
ret = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
|
||||
va_end(vargs);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = device_add(dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return dev;
|
||||
|
||||
error:
|
||||
put_device(dev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void iommu_device_destroy(struct device *dev)
|
||||
{
|
||||
if (!dev || IS_ERR(dev))
|
||||
return;
|
||||
|
||||
device_unregister(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* IOMMU drivers can indicate a device is managed by a given IOMMU using
|
||||
* this interface. A link to the device will be created in the "devices"
|
||||
* directory of the IOMMU device in sysfs and an "iommu" link will be
|
||||
* created under the linked device, pointing back at the IOMMU device.
|
||||
*/
|
||||
int iommu_device_link(struct device *dev, struct device *link)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!dev || IS_ERR(dev))
|
||||
return -ENODEV;
|
||||
|
||||
ret = sysfs_add_link_to_group(&dev->kobj, "devices",
|
||||
&link->kobj, dev_name(link));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_link_nowarn(&link->kobj, &dev->kobj, "iommu");
|
||||
if (ret)
|
||||
sysfs_remove_link_from_group(&dev->kobj, "devices",
|
||||
dev_name(link));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iommu_device_unlink(struct device *dev, struct device *link)
|
||||
{
|
||||
if (!dev || IS_ERR(dev))
|
||||
return;
|
||||
|
||||
sysfs_remove_link(&link->kobj, "iommu");
|
||||
sysfs_remove_link_from_group(&dev->kobj, "devices", dev_name(link));
|
||||
}
|
@ -187,6 +187,12 @@ extern int iommu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr,
|
||||
void *data);
|
||||
extern int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr,
|
||||
void *data);
|
||||
struct device *iommu_device_create(struct device *parent, void *drvdata,
|
||||
const struct attribute_group **groups,
|
||||
const char *fmt, ...);
|
||||
void iommu_device_destroy(struct device *dev);
|
||||
int iommu_device_link(struct device *dev, struct device *link);
|
||||
void iommu_device_unlink(struct device *dev, struct device *link);
|
||||
|
||||
/* Window handling function prototypes */
|
||||
extern int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
|
||||
@ -397,6 +403,26 @@ static inline int iommu_domain_set_attr(struct iommu_domain *domain,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct device *iommu_device_create(struct device *parent, void *drvdata,
|
||||
const struct attribute_group **groups,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
void iommu_device_destroy(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
int iommu_device_link(struct device *dev, struct device *link)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void iommu_device_unlink(struct device *dev, struct device *link)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOMMU_API */
|
||||
|
||||
#endif /* __LINUX_IOMMU_H */
|
||||
|
Loading…
Reference in New Issue
Block a user