aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */