aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/intel-iommu.c
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 /drivers/iommu/intel-iommu.c
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>
Diffstat (limited to 'drivers/iommu/intel-iommu.c')
-rw-r--r--drivers/iommu/intel-iommu.c77
1 files changed, 76 insertions, 1 deletions
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 = {