aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-06-12 18:12:31 -0400
committerJoerg Roedel <jroedel@suse.de>2014-07-04 06:35:59 -0400
commita5459cfece880e82778a60e6290ad6c0dd688a06 (patch)
treef032c49a317bc56b2d3a9883933b1b154a037fdf
parentc61959ecbbc6bf9034e65c8e8ef03fa9d1066f05 (diff)
iommu/vt-d: Make use of IOMMU sysfs support
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 <alex.williamson@redhat.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--Documentation/ABI/testing/sysfs-class-iommu-intel-iommu32
-rw-r--r--drivers/iommu/dmar.c9
-rw-r--r--drivers/iommu/intel-iommu.c77
-rw-r--r--include/linux/intel-iommu.h3
4 files changed, 120 insertions, 1 deletions
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 000000000000..258cc246d98e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-iommu-intel-iommu
@@ -0,0 +1,32 @@
1What: /sys/class/iommu/<iommu>/intel-iommu/address
2Date: June 2014
3KernelVersion: 3.17
4Contact: Alex Williamson <alex.williamson@redhat.com>
5Description:
6 Physical address of the VT-d DRHD for this IOMMU.
7 Format: %llx. This allows association of a sysfs
8 intel-iommu with a DMAR DRHD table entry.
9
10What: /sys/class/iommu/<iommu>/intel-iommu/cap
11Date: June 2014
12KernelVersion: 3.17
13Contact: Alex Williamson <alex.williamson@redhat.com>
14Description:
15 The cached hardware capability register value
16 of this DRHD unit. Format: %llx.
17
18What: /sys/class/iommu/<iommu>/intel-iommu/ecap
19Date: June 2014
20KernelVersion: 3.17
21Contact: Alex Williamson <alex.williamson@redhat.com>
22Description:
23 The cached hardware extended capability register
24 value of this DRHD unit. Format: %llx.
25
26What: /sys/class/iommu/<iommu>/intel-iommu/version
27Date: June 2014
28KernelVersion: 3.17
29Contact: Alex Williamson <alex.williamson@redhat.com>
30Description:
31 The architecture version as reported from the
32 VT-d VER_REG. Format: %d:%d, major:minor
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 9a4f05e5b23f..6744e2d4ff6f 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -38,6 +38,7 @@
38#include <linux/tboot.h> 38#include <linux/tboot.h>
39#include <linux/dmi.h> 39#include <linux/dmi.h>
40#include <linux/slab.h> 40#include <linux/slab.h>
41#include <linux/iommu.h>
41#include <asm/irq_remapping.h> 42#include <asm/irq_remapping.h>
42#include <asm/iommu_table.h> 43#include <asm/iommu_table.h>
43 44
@@ -980,6 +981,12 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
980 raw_spin_lock_init(&iommu->register_lock); 981 raw_spin_lock_init(&iommu->register_lock);
981 982
982 drhd->iommu = iommu; 983 drhd->iommu = iommu;
984
985 if (intel_iommu_enabled)
986 iommu->iommu_dev = iommu_device_create(NULL, iommu,
987 intel_iommu_groups,
988 iommu->name);
989
983 return 0; 990 return 0;
984 991
985 err_unmap: 992 err_unmap:
@@ -991,6 +998,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
991 998
992static void free_iommu(struct intel_iommu *iommu) 999static void free_iommu(struct intel_iommu *iommu)
993{ 1000{
1001 iommu_device_destroy(iommu->iommu_dev);
1002
994 if (iommu->irq) { 1003 if (iommu->irq) {
995 free_irq(iommu->irq, iommu); 1004 free_irq(iommu->irq, iommu);
996 irq_set_handler_data(iommu->irq, NULL); 1005 irq_set_handler_data(iommu->irq, NULL);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f38ec7ab7673..f9e5f84ee952 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3944,6 +3944,63 @@ static struct notifier_block intel_iommu_memory_nb = {
3944 .priority = 0 3944 .priority = 0
3945}; 3945};
3946 3946
3947
3948static ssize_t intel_iommu_show_version(struct device *dev,
3949 struct device_attribute *attr,
3950 char *buf)
3951{
3952 struct intel_iommu *iommu = dev_get_drvdata(dev);
3953 u32 ver = readl(iommu->reg + DMAR_VER_REG);
3954 return sprintf(buf, "%d:%d\n",
3955 DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver));
3956}
3957static DEVICE_ATTR(version, S_IRUGO, intel_iommu_show_version, NULL);
3958
3959static ssize_t intel_iommu_show_address(struct device *dev,
3960 struct device_attribute *attr,
3961 char *buf)
3962{
3963 struct intel_iommu *iommu = dev_get_drvdata(dev);
3964 return sprintf(buf, "%llx\n", iommu->reg_phys);
3965}
3966static DEVICE_ATTR(address, S_IRUGO, intel_iommu_show_address, NULL);
3967
3968static ssize_t intel_iommu_show_cap(struct device *dev,
3969 struct device_attribute *attr,
3970 char *buf)
3971{
3972 struct intel_iommu *iommu = dev_get_drvdata(dev);
3973 return sprintf(buf, "%llx\n", iommu->cap);
3974}
3975static DEVICE_ATTR(cap, S_IRUGO, intel_iommu_show_cap, NULL);
3976
3977static ssize_t intel_iommu_show_ecap(struct device *dev,
3978 struct device_attribute *attr,
3979 char *buf)
3980{
3981 struct intel_iommu *iommu = dev_get_drvdata(dev);
3982 return sprintf(buf, "%llx\n", iommu->ecap);
3983}
3984static DEVICE_ATTR(ecap, S_IRUGO, intel_iommu_show_ecap, NULL);
3985
3986static struct attribute *intel_iommu_attrs[] = {
3987 &dev_attr_version.attr,
3988 &dev_attr_address.attr,
3989 &dev_attr_cap.attr,
3990 &dev_attr_ecap.attr,
3991 NULL,
3992};
3993
3994static struct attribute_group intel_iommu_group = {
3995 .name = "intel-iommu",
3996 .attrs = intel_iommu_attrs,
3997};
3998
3999const struct attribute_group *intel_iommu_groups[] = {
4000 &intel_iommu_group,
4001 NULL,
4002};
4003
3947int __init intel_iommu_init(void) 4004int __init intel_iommu_init(void)
3948{ 4005{
3949 int ret = -ENODEV; 4006 int ret = -ENODEV;
@@ -4015,6 +4072,11 @@ int __init intel_iommu_init(void)
4015 4072
4016 init_iommu_pm_ops(); 4073 init_iommu_pm_ops();
4017 4074
4075 for_each_active_iommu(iommu, drhd)
4076 iommu->iommu_dev = iommu_device_create(NULL, iommu,
4077 intel_iommu_groups,
4078 iommu->name);
4079
4018 bus_set_iommu(&pci_bus_type, &intel_iommu_ops); 4080 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
4019 bus_register_notifier(&pci_bus_type, &device_nb); 4081 bus_register_notifier(&pci_bus_type, &device_nb);
4020 if (si_domain && !hw_pass_through) 4082 if (si_domain && !hw_pass_through)
@@ -4358,12 +4420,16 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4358 4420
4359static int intel_iommu_add_device(struct device *dev) 4421static int intel_iommu_add_device(struct device *dev)
4360{ 4422{
4423 struct intel_iommu *iommu;
4361 struct iommu_group *group; 4424 struct iommu_group *group;
4362 u8 bus, devfn; 4425 u8 bus, devfn;
4363 4426
4364 if (!device_to_iommu(dev, &bus, &devfn)) 4427 iommu = device_to_iommu(dev, &bus, &devfn);
4428 if (!iommu)
4365 return -ENODEV; 4429 return -ENODEV;
4366 4430
4431 iommu_device_link(iommu->iommu_dev, dev);
4432
4367 group = iommu_group_get_for_dev(dev); 4433 group = iommu_group_get_for_dev(dev);
4368 4434
4369 if (IS_ERR(group)) 4435 if (IS_ERR(group))
@@ -4375,7 +4441,16 @@ static int intel_iommu_add_device(struct device *dev)
4375 4441
4376static void intel_iommu_remove_device(struct device *dev) 4442static void intel_iommu_remove_device(struct device *dev)
4377{ 4443{
4444 struct intel_iommu *iommu;
4445 u8 bus, devfn;
4446
4447 iommu = device_to_iommu(dev, &bus, &devfn);
4448 if (!iommu)
4449 return;
4450
4378 iommu_group_remove_device(dev); 4451 iommu_group_remove_device(dev);
4452
4453 iommu_device_unlink(iommu->iommu_dev, dev);
4379} 4454}
4380 4455
4381static struct iommu_ops intel_iommu_ops = { 4456static struct iommu_ops intel_iommu_ops = {
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 0a2da5188217..a65208a8fe18 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -336,6 +336,7 @@ struct intel_iommu {
336#ifdef CONFIG_IRQ_REMAP 336#ifdef CONFIG_IRQ_REMAP
337 struct ir_table *ir_table; /* Interrupt remapping info */ 337 struct ir_table *ir_table; /* Interrupt remapping info */
338#endif 338#endif
339 struct device *iommu_dev; /* IOMMU-sysfs device */
339 int node; 340 int node;
340}; 341};
341 342
@@ -365,4 +366,6 @@ extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
365 366
366extern int dmar_ir_support(void); 367extern int dmar_ir_support(void);
367 368
369extern const struct attribute_group *intel_iommu_groups[];
370
368#endif 371#endif