aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2011-10-21 15:56:05 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2011-11-15 06:22:23 -0500
commit1460432cb513f0c16136ed132c20ecfbf8ccf942 (patch)
treef9802b729aa47d9c95fe2de5f41c511d3db7df4c
parent1ea6b8f48918282bdca0b32a34095504ee65bab5 (diff)
iommu: Add iommu_device_group callback and iommu_group sysfs entry
An IOMMU group is a set of devices for which the IOMMU cannot distinguish transactions. For PCI devices, a group often occurs when a PCI bridge is involved. Transactions from any device behind the bridge appear to be sourced from the bridge itself. We leave it to the IOMMU driver to define the grouping restraints for their platform. Using this new interface, the group for a device can be retrieved using the iommu_device_group() callback. Users will compare the value returned against the value returned for other devices to determine whether they are part of the same group. Devices with no group are not translated by the IOMMU. There should be no expectations about the group numbers as they may be arbitrarily assigned by the IOMMU driver and may not be persistent across boots. We also provide a sysfs interface to the group numbers here so that userspace can understand IOMMU dependencies between devices for managing safe, userspace drivers. [Some code changes by Joerg Roedel <joerg.roedel@amd.com>] Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
-rw-r--r--drivers/iommu/iommu.c60
-rw-r--r--include/linux/iommu.h7
2 files changed, 67 insertions, 0 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 2fb2963df553..9c35be4b333f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -25,8 +25,59 @@
25#include <linux/errno.h> 25#include <linux/errno.h>
26#include <linux/iommu.h> 26#include <linux/iommu.h>
27 27
28static ssize_t show_iommu_group(struct device *dev,
29 struct device_attribute *attr, char *buf)
30{
31 unsigned int groupid;
32
33 if (iommu_device_group(dev, &groupid))
34 return 0;
35
36 return sprintf(buf, "%u", groupid);
37}
38static DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL);
39
40static int add_iommu_group(struct device *dev, void *data)
41{
42 unsigned int groupid;
43
44 if (iommu_device_group(dev, &groupid) == 0)
45 return device_create_file(dev, &dev_attr_iommu_group);
46
47 return 0;
48}
49
50static int remove_iommu_group(struct device *dev)
51{
52 unsigned int groupid;
53
54 if (iommu_device_group(dev, &groupid) == 0)
55 device_remove_file(dev, &dev_attr_iommu_group);
56
57 return 0;
58}
59
60static int iommu_device_notifier(struct notifier_block *nb,
61 unsigned long action, void *data)
62{
63 struct device *dev = data;
64
65 if (action == BUS_NOTIFY_ADD_DEVICE)
66 return add_iommu_group(dev, NULL);
67 else if (action == BUS_NOTIFY_DEL_DEVICE)
68 return remove_iommu_group(dev);
69
70 return 0;
71}
72
73static struct notifier_block iommu_device_nb = {
74 .notifier_call = iommu_device_notifier,
75};
76
28static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops) 77static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops)
29{ 78{
79 bus_register_notifier(bus, &iommu_device_nb);
80 bus_for_each_dev(bus, NULL, NULL, add_iommu_group);
30} 81}
31 82
32/** 83/**
@@ -186,3 +237,12 @@ int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
186 return domain->ops->unmap(domain, iova, gfp_order); 237 return domain->ops->unmap(domain, iova, gfp_order);
187} 238}
188EXPORT_SYMBOL_GPL(iommu_unmap); 239EXPORT_SYMBOL_GPL(iommu_unmap);
240
241int iommu_device_group(struct device *dev, unsigned int *groupid)
242{
243 if (iommu_present(dev->bus) && dev->bus->iommu_ops->device_group)
244 return dev->bus->iommu_ops->device_group(dev, groupid);
245
246 return -ENODEV;
247}
248EXPORT_SYMBOL_GPL(iommu_device_group);
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 432acc4c054d..93617e7779a1 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -61,6 +61,7 @@ struct iommu_ops {
61 unsigned long iova); 61 unsigned long iova);
62 int (*domain_has_cap)(struct iommu_domain *domain, 62 int (*domain_has_cap)(struct iommu_domain *domain,
63 unsigned long cap); 63 unsigned long cap);
64 int (*device_group)(struct device *dev, unsigned int *groupid);
64}; 65};
65 66
66extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops); 67extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
@@ -81,6 +82,7 @@ extern int iommu_domain_has_cap(struct iommu_domain *domain,
81 unsigned long cap); 82 unsigned long cap);
82extern void iommu_set_fault_handler(struct iommu_domain *domain, 83extern void iommu_set_fault_handler(struct iommu_domain *domain,
83 iommu_fault_handler_t handler); 84 iommu_fault_handler_t handler);
85extern int iommu_device_group(struct device *dev, unsigned int *groupid);
84 86
85/** 87/**
86 * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework 88 * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
@@ -179,6 +181,11 @@ static inline void iommu_set_fault_handler(struct iommu_domain *domain,
179{ 181{
180} 182}
181 183
184static inline int iommu_device_group(struct device *dev, unsigned int *groupid);
185{
186 return -ENODEV;
187}
188
182#endif /* CONFIG_IOMMU_API */ 189#endif /* CONFIG_IOMMU_API */
183 190
184#endif /* __LINUX_IOMMU_H */ 191#endif /* __LINUX_IOMMU_H */