aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/iommu.c')
-rw-r--r--drivers/iommu/iommu.c114
1 files changed, 89 insertions, 25 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 6e6b6a11b3ce..2fb2963df553 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -16,6 +16,8 @@
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */ 17 */
18 18
19#include <linux/device.h>
20#include <linux/kernel.h>
19#include <linux/bug.h> 21#include <linux/bug.h>
20#include <linux/types.h> 22#include <linux/types.h>
21#include <linux/module.h> 23#include <linux/module.h>
@@ -23,32 +25,78 @@
23#include <linux/errno.h> 25#include <linux/errno.h>
24#include <linux/iommu.h> 26#include <linux/iommu.h>
25 27
26static struct iommu_ops *iommu_ops; 28static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops)
29{
30}
27 31
28void register_iommu(struct iommu_ops *ops) 32/**
33 * bus_set_iommu - set iommu-callbacks for the bus
34 * @bus: bus.
35 * @ops: the callbacks provided by the iommu-driver
36 *
37 * This function is called by an iommu driver to set the iommu methods
38 * used for a particular bus. Drivers for devices on that bus can use
39 * the iommu-api after these ops are registered.
40 * This special function is needed because IOMMUs are usually devices on
41 * the bus itself, so the iommu drivers are not initialized when the bus
42 * is set up. With this function the iommu-driver can set the iommu-ops
43 * afterwards.
44 */
45int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops)
29{ 46{
30 if (iommu_ops) 47 if (bus->iommu_ops != NULL)
31 BUG(); 48 return -EBUSY;
49
50 bus->iommu_ops = ops;
51
52 /* Do IOMMU specific setup for this bus-type */
53 iommu_bus_init(bus, ops);
32 54
33 iommu_ops = ops; 55 return 0;
34} 56}
57EXPORT_SYMBOL_GPL(bus_set_iommu);
35 58
36bool iommu_found(void) 59bool iommu_present(struct bus_type *bus)
37{ 60{
38 return iommu_ops != NULL; 61 return bus->iommu_ops != NULL;
39} 62}
40EXPORT_SYMBOL_GPL(iommu_found); 63EXPORT_SYMBOL_GPL(iommu_present);
41 64
42struct iommu_domain *iommu_domain_alloc(void) 65/**
66 * iommu_set_fault_handler() - set a fault handler for an iommu domain
67 * @domain: iommu domain
68 * @handler: fault handler
69 *
70 * This function should be used by IOMMU users which want to be notified
71 * whenever an IOMMU fault happens.
72 *
73 * The fault handler itself should return 0 on success, and an appropriate
74 * error code otherwise.
75 */
76void iommu_set_fault_handler(struct iommu_domain *domain,
77 iommu_fault_handler_t handler)
78{
79 BUG_ON(!domain);
80
81 domain->handler = handler;
82}
83EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
84
85struct iommu_domain *iommu_domain_alloc(struct bus_type *bus)
43{ 86{
44 struct iommu_domain *domain; 87 struct iommu_domain *domain;
45 int ret; 88 int ret;
46 89
90 if (bus == NULL || bus->iommu_ops == NULL)
91 return NULL;
92
47 domain = kmalloc(sizeof(*domain), GFP_KERNEL); 93 domain = kmalloc(sizeof(*domain), GFP_KERNEL);
48 if (!domain) 94 if (!domain)
49 return NULL; 95 return NULL;
50 96
51 ret = iommu_ops->domain_init(domain); 97 domain->ops = bus->iommu_ops;
98
99 ret = domain->ops->domain_init(domain);
52 if (ret) 100 if (ret)
53 goto out_free; 101 goto out_free;
54 102
@@ -63,62 +111,78 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
63 111
64void iommu_domain_free(struct iommu_domain *domain) 112void iommu_domain_free(struct iommu_domain *domain)
65{ 113{
66 iommu_ops->domain_destroy(domain); 114 if (likely(domain->ops->domain_destroy != NULL))
115 domain->ops->domain_destroy(domain);
116
67 kfree(domain); 117 kfree(domain);
68} 118}
69EXPORT_SYMBOL_GPL(iommu_domain_free); 119EXPORT_SYMBOL_GPL(iommu_domain_free);
70 120
71int iommu_attach_device(struct iommu_domain *domain, struct device *dev) 121int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
72{ 122{
73 return iommu_ops->attach_dev(domain, dev); 123 if (unlikely(domain->ops->attach_dev == NULL))
124 return -ENODEV;
125
126 return domain->ops->attach_dev(domain, dev);
74} 127}
75EXPORT_SYMBOL_GPL(iommu_attach_device); 128EXPORT_SYMBOL_GPL(iommu_attach_device);
76 129
77void iommu_detach_device(struct iommu_domain *domain, struct device *dev) 130void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
78{ 131{
79 iommu_ops->detach_dev(domain, dev); 132 if (unlikely(domain->ops->detach_dev == NULL))
133 return;
134
135 domain->ops->detach_dev(domain, dev);
80} 136}
81EXPORT_SYMBOL_GPL(iommu_detach_device); 137EXPORT_SYMBOL_GPL(iommu_detach_device);
82 138
83phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, 139phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
84 unsigned long iova) 140 unsigned long iova)
85{ 141{
86 return iommu_ops->iova_to_phys(domain, iova); 142 if (unlikely(domain->ops->iova_to_phys == NULL))
143 return 0;
144
145 return domain->ops->iova_to_phys(domain, iova);
87} 146}
88EXPORT_SYMBOL_GPL(iommu_iova_to_phys); 147EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
89 148
90int iommu_domain_has_cap(struct iommu_domain *domain, 149int iommu_domain_has_cap(struct iommu_domain *domain,
91 unsigned long cap) 150 unsigned long cap)
92{ 151{
93 return iommu_ops->domain_has_cap(domain, cap); 152 if (unlikely(domain->ops->domain_has_cap == NULL))
153 return 0;
154
155 return domain->ops->domain_has_cap(domain, cap);
94} 156}
95EXPORT_SYMBOL_GPL(iommu_domain_has_cap); 157EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
96 158
97int iommu_map(struct iommu_domain *domain, unsigned long iova, 159int iommu_map(struct iommu_domain *domain, unsigned long iova,
98 phys_addr_t paddr, int gfp_order, int prot) 160 phys_addr_t paddr, int gfp_order, int prot)
99{ 161{
100 unsigned long invalid_mask;
101 size_t size; 162 size_t size;
102 163
103 size = 0x1000UL << gfp_order; 164 if (unlikely(domain->ops->map == NULL))
104 invalid_mask = size - 1; 165 return -ENODEV;
105 166
106 BUG_ON((iova | paddr) & invalid_mask); 167 size = PAGE_SIZE << gfp_order;
107 168
108 return iommu_ops->map(domain, iova, paddr, gfp_order, prot); 169 BUG_ON(!IS_ALIGNED(iova | paddr, size));
170
171 return domain->ops->map(domain, iova, paddr, gfp_order, prot);
109} 172}
110EXPORT_SYMBOL_GPL(iommu_map); 173EXPORT_SYMBOL_GPL(iommu_map);
111 174
112int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order) 175int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
113{ 176{
114 unsigned long invalid_mask;
115 size_t size; 177 size_t size;
116 178
117 size = 0x1000UL << gfp_order; 179 if (unlikely(domain->ops->unmap == NULL))
118 invalid_mask = size - 1; 180 return -ENODEV;
181
182 size = PAGE_SIZE << gfp_order;
119 183
120 BUG_ON(iova & invalid_mask); 184 BUG_ON(!IS_ALIGNED(iova, size));
121 185
122 return iommu_ops->unmap(domain, iova, gfp_order); 186 return domain->ops->unmap(domain, iova, gfp_order);
123} 187}
124EXPORT_SYMBOL_GPL(iommu_unmap); 188EXPORT_SYMBOL_GPL(iommu_unmap);