Users want to know the features of their hardware and we need a better
way to get it than parsing it out of dmesg. This series creates an
IOMMU class and allows drivers to create and destroy a device within
that class. Drivers may also link and unlink devices to expose the
association of a device to a specific hardware unit and create
attribute groups to expose further information about the specific
IOMMU.
An example use case for this would be to determine whether the IOMMU
for a device supports super-pages, which can have performance
implications for a device assignment scenario. A user with multiple
IOMMU units may also want to factor load per IOMMU into their hardware
layout. This helps to expose those connections.
I posted an RFC for this last month, but there were no comments. This
version officialy includes AMD-Vi support and removes the kobject used
for creating the "devices" subdirectory, instead using an empty
attribute group. I've tried not to duplicate any information
available elsewhere for the user, for example in the DMAR or IVRS
tables. This means that while I think it might be interesting to
expose things like RMRR, the user already has access to those by
parsing the appropriate firmware table. I welcome any additional
IOMMU driver implementaitons. Thanks,
Alex
---
Alex Williamson (3):
iommu: Add sysfs support for IOMMUs
iommu/intel: Make use of IOMMU sysfs support
iommu/amd: Add sysfs support
Documentation/ABI/testing/sysfs-class-iommu | 17 +++
.../ABI/testing/sysfs-class-iommu-amd-iommu | 14 ++
.../ABI/testing/sysfs-class-iommu-intel-iommu | 32 +++++
drivers/iommu/Makefile | 1
drivers/iommu/amd_iommu.c | 6 +
drivers/iommu/amd_iommu_init.c | 38 ++++++
drivers/iommu/amd_iommu_types.h | 3
drivers/iommu/dmar.c | 9 +
drivers/iommu/intel-iommu.c | 77 +++++++++++-
drivers/iommu/iommu-sysfs.c | 133 ++++++++++++++++++++
include/linux/intel-iommu.h | 3
include/linux/iommu.h | 26 ++++
12 files changed, 358 insertions(+), 1 deletion(-)
create mode 100644 Documentation/ABI/testing/sysfs-class-iommu
create mode 100644 Documentation/ABI/testing/sysfs-class-iommu-amd-iommu
create mode 100644 Documentation/ABI/testing/sysfs-class-iommu-intel-iommu
create mode 100644 drivers/iommu/iommu-sysfs.c
Register our DRHD IOMMUs, cross link devices, and provide a base set
of attributes for the IOMMU. Note that IRQ remapping support parses
the DMAR table very early in boot, well before the iommu_class can
reasonably be setup, so our registration is split between
intel_iommu_init(), which occurs later, and alloc_iommu(), which
typically occurs much earlier, but may happen at any time later
with IOMMU hot-add support.
On a typical desktop system, this provides the following (pruned):
$ find /sys | grep dmar
/sys/devices/virtual/iommu/dmar0
/sys/devices/virtual/iommu/dmar0/devices
/sys/devices/virtual/iommu/dmar0/devices/0000:00:02.0
/sys/devices/virtual/iommu/dmar0/intel-iommu
/sys/devices/virtual/iommu/dmar0/intel-iommu/cap
/sys/devices/virtual/iommu/dmar0/intel-iommu/ecap
/sys/devices/virtual/iommu/dmar0/intel-iommu/address
/sys/devices/virtual/iommu/dmar0/intel-iommu/version
/sys/devices/virtual/iommu/dmar1
/sys/devices/virtual/iommu/dmar1/devices
/sys/devices/virtual/iommu/dmar1/devices/0000:00:00.0
/sys/devices/virtual/iommu/dmar1/devices/0000:00:01.0
/sys/devices/virtual/iommu/dmar1/devices/0000:00:16.0
/sys/devices/virtual/iommu/dmar1/devices/0000:00:1a.0
/sys/devices/virtual/iommu/dmar1/devices/0000:00:1b.0
/sys/devices/virtual/iommu/dmar1/devices/0000:00:1c.0
...
/sys/devices/virtual/iommu/dmar1/intel-iommu
/sys/devices/virtual/iommu/dmar1/intel-iommu/cap
/sys/devices/virtual/iommu/dmar1/intel-iommu/ecap
/sys/devices/virtual/iommu/dmar1/intel-iommu/address
/sys/devices/virtual/iommu/dmar1/intel-iommu/version
/sys/class/iommu/dmar0
/sys/class/iommu/dmar1
(devices also link back to the dmar units)
This makes address, version, capabilities, and extended capabilities
available, just like printed on boot. I've tried not to duplicate
data that can be found in the DMAR table, with the exception of the
address, which provides an easy way to associate the sysfs device with
a DRHD entry in the DMAR. It's tempting to add scopes and RMRR data
here, but the full DMAR table is already exposed under /sys/firmware/
and therefore already provides a way for userspace to learn such
details.
Signed-off-by: Alex Williamson <[email protected]>
---
.../ABI/testing/sysfs-class-iommu-intel-iommu | 32 ++++++++
drivers/iommu/dmar.c | 9 ++
drivers/iommu/intel-iommu.c | 77 ++++++++++++++++++++
include/linux/intel-iommu.h | 3 +
4 files changed, 120 insertions(+), 1 deletion(-)
create mode 100644 Documentation/ABI/testing/sysfs-class-iommu-intel-iommu
diff --git a/Documentation/ABI/testing/sysfs-class-iommu-intel-iommu b/Documentation/ABI/testing/sysfs-class-iommu-intel-iommu
new file mode 100644
index 0000000..258cc246
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-iommu-intel-iommu
@@ -0,0 +1,32 @@
+What: /sys/class/iommu/<iommu>/intel-iommu/address
+Date: June 2014
+KernelVersion: 3.17
+Contact: Alex Williamson <[email protected]>
+Description:
+ Physical address of the VT-d DRHD for this IOMMU.
+ Format: %llx. This allows association of a sysfs
+ intel-iommu with a DMAR DRHD table entry.
+
+What: /sys/class/iommu/<iommu>/intel-iommu/cap
+Date: June 2014
+KernelVersion: 3.17
+Contact: Alex Williamson <[email protected]>
+Description:
+ The cached hardware capability register value
+ of this DRHD unit. Format: %llx.
+
+What: /sys/class/iommu/<iommu>/intel-iommu/ecap
+Date: June 2014
+KernelVersion: 3.17
+Contact: Alex Williamson <[email protected]>
+Description:
+ The cached hardware extended capability register
+ value of this DRHD unit. Format: %llx.
+
+What: /sys/class/iommu/<iommu>/intel-iommu/version
+Date: June 2014
+KernelVersion: 3.17
+Contact: Alex Williamson <[email protected]>
+Description:
+ The architecture version as reported from the
+ VT-d VER_REG. Format: %d:%d, major:minor
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 39f8b71..b240f6a 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -38,6 +38,7 @@
#include <linux/tboot.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <linux/iommu.h>
#include <asm/irq_remapping.h>
#include <asm/iommu_table.h>
@@ -980,6 +981,12 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
raw_spin_lock_init(&iommu->register_lock);
drhd->iommu = iommu;
+
+ if (intel_iommu_enabled)
+ iommu->iommu_dev = iommu_device_create(NULL, iommu,
+ intel_iommu_groups,
+ iommu->name);
+
return 0;
err_unmap:
@@ -991,6 +998,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
static void free_iommu(struct intel_iommu *iommu)
{
+ iommu_device_destroy(iommu->iommu_dev);
+
if (iommu->irq) {
free_irq(iommu->irq, iommu);
irq_set_handler_data(iommu->irq, NULL);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 41db805..3205142 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3930,6 +3930,63 @@ static struct notifier_block intel_iommu_memory_nb = {
.priority = 0
};
+
+static ssize_t intel_iommu_show_version(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct intel_iommu *iommu = dev_get_drvdata(dev);
+ u32 ver = readl(iommu->reg + DMAR_VER_REG);
+ return sprintf(buf, "%d:%d\n",
+ DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver));
+}
+static DEVICE_ATTR(version, S_IRUGO, intel_iommu_show_version, NULL);
+
+static ssize_t intel_iommu_show_address(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct intel_iommu *iommu = dev_get_drvdata(dev);
+ return sprintf(buf, "%llx\n", iommu->reg_phys);
+}
+static DEVICE_ATTR(address, S_IRUGO, intel_iommu_show_address, NULL);
+
+static ssize_t intel_iommu_show_cap(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct intel_iommu *iommu = dev_get_drvdata(dev);
+ return sprintf(buf, "%llx\n", iommu->cap);
+}
+static DEVICE_ATTR(cap, S_IRUGO, intel_iommu_show_cap, NULL);
+
+static ssize_t intel_iommu_show_ecap(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct intel_iommu *iommu = dev_get_drvdata(dev);
+ return sprintf(buf, "%llx\n", iommu->ecap);
+}
+static DEVICE_ATTR(ecap, S_IRUGO, intel_iommu_show_ecap, NULL);
+
+static struct attribute *intel_iommu_attrs[] = {
+ &dev_attr_version.attr,
+ &dev_attr_address.attr,
+ &dev_attr_cap.attr,
+ &dev_attr_ecap.attr,
+ NULL,
+};
+
+static struct attribute_group intel_iommu_group = {
+ .name = "intel-iommu",
+ .attrs = intel_iommu_attrs,
+};
+
+const struct attribute_group *intel_iommu_groups[] = {
+ &intel_iommu_group,
+ NULL,
+};
+
int __init intel_iommu_init(void)
{
int ret = -ENODEV;
@@ -4001,6 +4058,11 @@ int __init intel_iommu_init(void)
init_iommu_pm_ops();
+ for_each_active_iommu(iommu, drhd)
+ iommu->iommu_dev = iommu_device_create(NULL, iommu,
+ intel_iommu_groups,
+ iommu->name);
+
bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
bus_register_notifier(&pci_bus_type, &device_nb);
if (si_domain && !hw_pass_through)
@@ -4359,12 +4421,16 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
static int intel_iommu_add_device(struct device *dev)
{
+ struct intel_iommu *iommu;
struct iommu_group *group;
u8 bus, devfn;
- if (!device_to_iommu(dev, &bus, &devfn))
+ iommu = device_to_iommu(dev, &bus, &devfn);
+ if (!iommu)
return -ENODEV;
+ iommu_device_link(iommu->iommu_dev, dev);
+
group = iommu_group_get_for_dev(dev);
if (IS_ERR(group))
@@ -4376,7 +4442,16 @@ static int intel_iommu_add_device(struct device *dev)
static void intel_iommu_remove_device(struct device *dev)
{
+ struct intel_iommu *iommu;
+ u8 bus, devfn;
+
+ iommu = device_to_iommu(dev, &bus, &devfn);
+ if (!iommu)
+ return;
+
iommu_group_remove_device(dev);
+
+ iommu_device_unlink(iommu->iommu_dev, dev);
}
static struct iommu_ops intel_iommu_ops = {
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 0a2da51..a65208a 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -336,6 +336,7 @@ struct intel_iommu {
#ifdef CONFIG_IRQ_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
#endif
+ struct device *iommu_dev; /* IOMMU-sysfs device */
int node;
};
@@ -365,4 +366,6 @@ extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
extern int dmar_ir_support(void);
+extern const struct attribute_group *intel_iommu_groups[];
+
#endif
AMD-Vi support for IOMMU sysfs. This allows us to associate devices
with a specific IOMMU device and examine the capabilities and features
of that IOMMU. The AMD IOMMU is hosted on and actual PCI device, so
we make that device the parent for the IOMMU class device. This
initial implementaiton exposes only the capability header and extended
features register for the IOMMU.
# find /sys | grep ivhd
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:00.0
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:02.0
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:04.0
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:09.0
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:11.0
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:12.0
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:12.2
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/devices/0000:00:13.0
...
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/power
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/power/control
...
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/device
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/subsystem
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/amd-iommu
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/amd-iommu/cap
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/amd-iommu/features
/sys/devices/pci0000:00/0000:00:00.2/iommu/ivhd0/uevent
/sys/class/iommu/ivhd0
Signed-off-by: Alex Williamson <[email protected]>
---
.../ABI/testing/sysfs-class-iommu-amd-iommu | 14 +++++++
drivers/iommu/amd_iommu.c | 6 +++
drivers/iommu/amd_iommu_init.c | 38 ++++++++++++++++++++
drivers/iommu/amd_iommu_types.h | 3 ++
4 files changed, 61 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-iommu-amd-iommu
diff --git a/Documentation/ABI/testing/sysfs-class-iommu-amd-iommu b/Documentation/ABI/testing/sysfs-class-iommu-amd-iommu
new file mode 100644
index 0000000..d6ba8e8
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-iommu-amd-iommu
@@ -0,0 +1,14 @@
+What: /sys/class/iommu/<iommu>/amd-iommu/cap
+Date: June 2014
+KernelVersion: 3.17
+Contact: Alex Williamson <[email protected]>
+Description:
+ IOMMU capability header as documented in the AMD IOMMU
+ specification. Format: %x
+
+What: /sys/class/iommu/<iommu>/amd-iommu/features
+Date: June 2014
+KernelVersion: 3.17
+Contact: Alex Williamson <[email protected]>
+Description:
+ Extended features of the IOMMU. Format: %llx
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index ca85615..83a43b2 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -379,6 +379,9 @@ static int iommu_init_device(struct device *dev)
dev->archdata.iommu = dev_data;
+ iommu_device_link(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
+ dev);
+
return 0;
}
@@ -403,6 +406,9 @@ static void iommu_uninit_device(struct device *dev)
if (!dev_data)
return;
+ iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
+ dev);
+
iommu_group_remove_device(dev);
/* Unlink from alias, it may change if another device is re-plugged */
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 0e08545..3783e0b 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -26,6 +26,7 @@
#include <linux/msi.h>
#include <linux/amd-iommu.h>
#include <linux/export.h>
+#include <linux/iommu.h>
#include <asm/pci-direct.h>
#include <asm/iommu.h>
#include <asm/gart.h>
@@ -1197,6 +1198,39 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu)
iommu->max_counters = (u8) ((val >> 7) & 0xf);
}
+static ssize_t amd_iommu_show_cap(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amd_iommu *iommu = dev_get_drvdata(dev);
+ return sprintf(buf, "%x\n", iommu->cap);
+}
+static DEVICE_ATTR(cap, S_IRUGO, amd_iommu_show_cap, NULL);
+
+static ssize_t amd_iommu_show_features(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amd_iommu *iommu = dev_get_drvdata(dev);
+ return sprintf(buf, "%llx\n", iommu->features);
+}
+static DEVICE_ATTR(features, S_IRUGO, amd_iommu_show_features, NULL);
+
+static struct attribute *amd_iommu_attrs[] = {
+ &dev_attr_cap.attr,
+ &dev_attr_features.attr,
+ NULL,
+};
+
+static struct attribute_group amd_iommu_group = {
+ .name = "amd-iommu",
+ .attrs = amd_iommu_attrs,
+};
+
+static const struct attribute_group *amd_iommu_groups[] = {
+ &amd_iommu_group,
+ NULL,
+};
static int iommu_init_pci(struct amd_iommu *iommu)
{
@@ -1297,6 +1331,10 @@ static int iommu_init_pci(struct amd_iommu *iommu)
amd_iommu_erratum_746_workaround(iommu);
+ iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
+ amd_iommu_groups, "ivhd%d",
+ iommu->index);
+
return pci_enable_device(iommu->dev);
}
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 7277a20..557a20e 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -577,6 +577,9 @@ struct amd_iommu {
/* default dma_ops domain for that IOMMU */
struct dma_ops_domain *default_dom;
+ /* IOMMU sysfs device */
+ struct device *iommu_dev;
+
/*
* We can't rely on the BIOS to restore all values on reinit, so we
* need to stash them
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 <[email protected]>
---
Documentation/ABI/testing/sysfs-class-iommu | 17 +++
drivers/iommu/Makefile | 1
drivers/iommu/iommu-sysfs.c | 133 +++++++++++++++++++++++++++
include/linux/iommu.h | 26 +++++
4 files changed, 177 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-iommu
create mode 100644 drivers/iommu/iommu-sysfs.c
diff --git a/Documentation/ABI/testing/sysfs-class-iommu b/Documentation/ABI/testing/sysfs-class-iommu
new file mode 100644
index 0000000..6d0a1b4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-iommu
@@ -0,0 +1,17 @@
+What: /sys/class/iommu/<iommu>/devices/
+Date: June 2014
+KernelVersion: 3.17
+Contact: Alex Williamson <[email protected]>
+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 <[email protected]>
+Description:
+ IOMMU drivers are able to link the IOMMU for a
+ given device here to allow association of device to
+ IOMMU.
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 5d58bf1..437c231 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -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
diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c
new file mode 100644
index 0000000..d693923
--- /dev/null
+++ b/drivers/iommu/iommu-sysfs.c
@@ -0,0 +1,133 @@
+/*
+ * IOMMU sysfs class support
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All rights reserved.
+ * Author: Alex Williamson <[email protected]>
+ *
+ * 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));
+}
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index a2e5843..7fd16e3 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -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 */
On Thu, Jun 12, 2014 at 04:12:18PM -0600, Alex Williamson wrote:
> Alex Williamson (3):
> iommu: Add sysfs support for IOMMUs
> iommu/intel: Make use of IOMMU sysfs support
> iommu/amd: Add sysfs support
I like the general approach. But why do you only enable the x86 iommus?
Some ARM IOMMUs and PAMU would certainly also benefit from a sysfs
representation of which device is translated by which IOMMU.
Joerg
On Mon, 2014-06-16 at 17:16 +0200, Joerg Roedel wrote:
> On Thu, Jun 12, 2014 at 04:12:18PM -0600, Alex Williamson wrote:
> > Alex Williamson (3):
> > iommu: Add sysfs support for IOMMUs
> > iommu/intel: Make use of IOMMU sysfs support
> > iommu/amd: Add sysfs support
>
> I like the general approach. But why do you only enable the x86 iommus?
> Some ARM IOMMUs and PAMU would certainly also benefit from a sysfs
> representation of which device is translated by which IOMMU.
Only because I have no ability to test the others platforms. I'd be
thrilled if someone working on those IOMMUs could validate this on
non-x86. Thanks,
Alex
On Mon, 2014-06-16 at 09:24 -0600, Alex Williamson wrote:
> On Mon, 2014-06-16 at 17:16 +0200, Joerg Roedel wrote:
> > On Thu, Jun 12, 2014 at 04:12:18PM -0600, Alex Williamson wrote:
> > > Alex Williamson (3):
> > > iommu: Add sysfs support for IOMMUs
> > > iommu/intel: Make use of IOMMU sysfs support
> > > iommu/amd: Add sysfs support
> >
> > I like the general approach. But why do you only enable the x86 iommus?
> > Some ARM IOMMUs and PAMU would certainly also benefit from a sysfs
> > representation of which device is translated by which IOMMU.
>
> Only because I have no ability to test the others platforms. I'd be
> thrilled if someone working on those IOMMUs could validate this on
> non-x86. Thanks,
Should I re-send this series or are you hoping I'll attempt to piece
together a non-x86 user for which I have no hardware and can't test?
Varun, do you have any interest in this for the fsl iommu to try a proof
of concept? Thanks,
Alex
Hi Alex,
This is on my todo list. I have a requirement for adding sysfs support for PAMU.
Regards
Varun
> -----Original Message-----
> From: Alex Williamson [mailto:[email protected]]
> Sent: Thursday, July 03, 2014 9:39 PM
> To: Joerg Roedel
> Cc: [email protected]; [email protected]; linux-
> [email protected]; Sethi Varun-B16395
> Subject: Re: [PATCH 0/3] iommu: Expose IOMMU information in sysfs
>
> On Mon, 2014-06-16 at 09:24 -0600, Alex Williamson wrote:
> > On Mon, 2014-06-16 at 17:16 +0200, Joerg Roedel wrote:
> > > On Thu, Jun 12, 2014 at 04:12:18PM -0600, Alex Williamson wrote:
> > > > Alex Williamson (3):
> > > > iommu: Add sysfs support for IOMMUs
> > > > iommu/intel: Make use of IOMMU sysfs support
> > > > iommu/amd: Add sysfs support
> > >
> > > I like the general approach. But why do you only enable the x86
> iommus?
> > > Some ARM IOMMUs and PAMU would certainly also benefit from a sysfs
> > > representation of which device is translated by which IOMMU.
> >
> > Only because I have no ability to test the others platforms. I'd be
> > thrilled if someone working on those IOMMUs could validate this on
> > non-x86. Thanks,
>
> Should I re-send this series or are you hoping I'll attempt to piece
> together a non-x86 user for which I have no hardware and can't test?
> Varun, do you have any interest in this for the fsl iommu to try a proof
> of concept? Thanks,
>
> Alex
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m????????????I?
On Thu, Jun 12, 2014 at 04:12:18PM -0600, Alex Williamson wrote:
> Alex Williamson (3):
> iommu: Add sysfs support for IOMMUs
> iommu/intel: Make use of IOMMU sysfs support
> iommu/amd: Add sysfs support
>
>
> Documentation/ABI/testing/sysfs-class-iommu | 17 +++
> .../ABI/testing/sysfs-class-iommu-amd-iommu | 14 ++
> .../ABI/testing/sysfs-class-iommu-intel-iommu | 32 +++++
> drivers/iommu/Makefile | 1
> drivers/iommu/amd_iommu.c | 6 +
> drivers/iommu/amd_iommu_init.c | 38 ++++++
> drivers/iommu/amd_iommu_types.h | 3
> drivers/iommu/dmar.c | 9 +
> drivers/iommu/intel-iommu.c | 77 +++++++++++-
> drivers/iommu/iommu-sysfs.c | 133 ++++++++++++++++++++
> include/linux/intel-iommu.h | 3
> include/linux/iommu.h | 26 ++++
> 12 files changed, 358 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/ABI/testing/sysfs-class-iommu
> create mode 100644 Documentation/ABI/testing/sysfs-class-iommu-amd-iommu
> create mode 100644 Documentation/ABI/testing/sysfs-class-iommu-intel-iommu
> create mode 100644 drivers/iommu/iommu-sysfs.c
Also applied to the core branch, thanks Alex.