Blame view

drivers/iommu/iommu.c 4.66 KB
fc2100eb4   Joerg Roedel   add frontend impl...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
   * Author: Joerg Roedel <joerg.roedel@amd.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published
   * by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
905d66c1e   Joerg Roedel   iommu/core: Add b...
18
  #include <linux/device.h>
409981884   Ohad Ben-Cohen   iommu/core: use t...
19
  #include <linux/kernel.h>
fc2100eb4   Joerg Roedel   add frontend impl...
20
21
  #include <linux/bug.h>
  #include <linux/types.h>
60db40278   Andrew Morton   drivers/base/iomm...
22
23
  #include <linux/module.h>
  #include <linux/slab.h>
fc2100eb4   Joerg Roedel   add frontend impl...
24
25
  #include <linux/errno.h>
  #include <linux/iommu.h>
ff21776d1   Joerg Roedel   Driver core: Add ...
26
27
28
  static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops)
  {
  }
fc2100eb4   Joerg Roedel   add frontend impl...
29

ff21776d1   Joerg Roedel   Driver core: Add ...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  /**
   * bus_set_iommu - set iommu-callbacks for the bus
   * @bus: bus.
   * @ops: the callbacks provided by the iommu-driver
   *
   * This function is called by an iommu driver to set the iommu methods
   * used for a particular bus. Drivers for devices on that bus can use
   * the iommu-api after these ops are registered.
   * This special function is needed because IOMMUs are usually devices on
   * the bus itself, so the iommu drivers are not initialized when the bus
   * is set up. With this function the iommu-driver can set the iommu-ops
   * afterwards.
   */
  int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops)
fc2100eb4   Joerg Roedel   add frontend impl...
44
  {
ff21776d1   Joerg Roedel   Driver core: Add ...
45
46
  	if (bus->iommu_ops != NULL)
  		return -EBUSY;
fc2100eb4   Joerg Roedel   add frontend impl...
47

ff21776d1   Joerg Roedel   Driver core: Add ...
48
49
50
51
  	bus->iommu_ops = ops;
  
  	/* Do IOMMU specific setup for this bus-type */
  	iommu_bus_init(bus, ops);
fc2100eb4   Joerg Roedel   add frontend impl...
52

ff21776d1   Joerg Roedel   Driver core: Add ...
53
  	return 0;
fc2100eb4   Joerg Roedel   add frontend impl...
54
  }
ff21776d1   Joerg Roedel   Driver core: Add ...
55
  EXPORT_SYMBOL_GPL(bus_set_iommu);
fc2100eb4   Joerg Roedel   add frontend impl...
56

a1b60c1cd   Joerg Roedel   iommu/core: Conve...
57
  bool iommu_present(struct bus_type *bus)
fc2100eb4   Joerg Roedel   add frontend impl...
58
  {
94441c3bd   Joerg Roedel   iommu/core: Remov...
59
  	return bus->iommu_ops != NULL;
fc2100eb4   Joerg Roedel   add frontend impl...
60
  }
a1b60c1cd   Joerg Roedel   iommu/core: Conve...
61
  EXPORT_SYMBOL_GPL(iommu_present);
fc2100eb4   Joerg Roedel   add frontend impl...
62

4f3f8d9db   Ohad Ben-Cohen   iommu/core: Add f...
63
64
65
66
  /**
   * iommu_set_fault_handler() - set a fault handler for an iommu domain
   * @domain: iommu domain
   * @handler: fault handler
0ed6d2d27   Ohad Ben-Cohen   iommu/core: let d...
67
68
69
70
71
72
   *
   * This function should be used by IOMMU users which want to be notified
   * whenever an IOMMU fault happens.
   *
   * The fault handler itself should return 0 on success, and an appropriate
   * error code otherwise.
4f3f8d9db   Ohad Ben-Cohen   iommu/core: Add f...
73
74
75
76
77
78
79
80
   */
  void iommu_set_fault_handler(struct iommu_domain *domain,
  					iommu_fault_handler_t handler)
  {
  	BUG_ON(!domain);
  
  	domain->handler = handler;
  }
30bd918c7   Ohad Ben-Cohen   iommu/core: expor...
81
  EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
4f3f8d9db   Ohad Ben-Cohen   iommu/core: Add f...
82

905d66c1e   Joerg Roedel   iommu/core: Add b...
83
  struct iommu_domain *iommu_domain_alloc(struct bus_type *bus)
fc2100eb4   Joerg Roedel   add frontend impl...
84
85
86
  {
  	struct iommu_domain *domain;
  	int ret;
94441c3bd   Joerg Roedel   iommu/core: Remov...
87
  	if (bus == NULL || bus->iommu_ops == NULL)
905d66c1e   Joerg Roedel   iommu/core: Add b...
88
  		return NULL;
fc2100eb4   Joerg Roedel   add frontend impl...
89
90
91
  	domain = kmalloc(sizeof(*domain), GFP_KERNEL);
  	if (!domain)
  		return NULL;
94441c3bd   Joerg Roedel   iommu/core: Remov...
92
  	domain->ops = bus->iommu_ops;
905d66c1e   Joerg Roedel   iommu/core: Add b...
93

94441c3bd   Joerg Roedel   iommu/core: Remov...
94
  	ret = domain->ops->domain_init(domain);
fc2100eb4   Joerg Roedel   add frontend impl...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  	if (ret)
  		goto out_free;
  
  	return domain;
  
  out_free:
  	kfree(domain);
  
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(iommu_domain_alloc);
  
  void iommu_domain_free(struct iommu_domain *domain)
  {
e5aa7f007   Joerg Roedel   iommu/core: Use b...
109
110
  	if (likely(domain->ops->domain_destroy != NULL))
  		domain->ops->domain_destroy(domain);
fc2100eb4   Joerg Roedel   add frontend impl...
111
112
113
114
115
116
  	kfree(domain);
  }
  EXPORT_SYMBOL_GPL(iommu_domain_free);
  
  int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
  {
e5aa7f007   Joerg Roedel   iommu/core: Use b...
117
118
119
120
  	if (unlikely(domain->ops->attach_dev == NULL))
  		return -ENODEV;
  
  	return domain->ops->attach_dev(domain, dev);
fc2100eb4   Joerg Roedel   add frontend impl...
121
122
123
124
125
  }
  EXPORT_SYMBOL_GPL(iommu_attach_device);
  
  void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
  {
e5aa7f007   Joerg Roedel   iommu/core: Use b...
126
127
128
129
  	if (unlikely(domain->ops->detach_dev == NULL))
  		return;
  
  	domain->ops->detach_dev(domain, dev);
fc2100eb4   Joerg Roedel   add frontend impl...
130
131
  }
  EXPORT_SYMBOL_GPL(iommu_detach_device);
fc2100eb4   Joerg Roedel   add frontend impl...
132
133
134
  phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
  			       unsigned long iova)
  {
e5aa7f007   Joerg Roedel   iommu/core: Use b...
135
136
137
138
  	if (unlikely(domain->ops->iova_to_phys == NULL))
  		return 0;
  
  	return domain->ops->iova_to_phys(domain, iova);
fc2100eb4   Joerg Roedel   add frontend impl...
139
140
  }
  EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
dbb9fd863   Sheng Yang   iommu: Add domain...
141
142
143
144
  
  int iommu_domain_has_cap(struct iommu_domain *domain,
  			 unsigned long cap)
  {
e5aa7f007   Joerg Roedel   iommu/core: Use b...
145
146
147
148
  	if (unlikely(domain->ops->domain_has_cap == NULL))
  		return 0;
  
  	return domain->ops->domain_has_cap(domain, cap);
dbb9fd863   Sheng Yang   iommu: Add domain...
149
150
  }
  EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
cefc53c7f   Joerg Roedel   iommu-api: Add io...
151
152
153
154
  
  int iommu_map(struct iommu_domain *domain, unsigned long iova,
  	      phys_addr_t paddr, int gfp_order, int prot)
  {
cefc53c7f   Joerg Roedel   iommu-api: Add io...
155
  	size_t size;
e5aa7f007   Joerg Roedel   iommu/core: Use b...
156
157
  	if (unlikely(domain->ops->map == NULL))
  		return -ENODEV;
cefc53c7f   Joerg Roedel   iommu-api: Add io...
158

85410340e   Joerg Roedel   iommu/core: Use P...
159
  	size         = PAGE_SIZE << gfp_order;
cefc53c7f   Joerg Roedel   iommu-api: Add io...
160

409981884   Ohad Ben-Cohen   iommu/core: use t...
161
  	BUG_ON(!IS_ALIGNED(iova | paddr, size));
cefc53c7f   Joerg Roedel   iommu-api: Add io...
162

e5aa7f007   Joerg Roedel   iommu/core: Use b...
163
  	return domain->ops->map(domain, iova, paddr, gfp_order, prot);
cefc53c7f   Joerg Roedel   iommu-api: Add io...
164
165
166
167
168
  }
  EXPORT_SYMBOL_GPL(iommu_map);
  
  int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
  {
cefc53c7f   Joerg Roedel   iommu-api: Add io...
169
  	size_t size;
e5aa7f007   Joerg Roedel   iommu/core: Use b...
170
171
  	if (unlikely(domain->ops->unmap == NULL))
  		return -ENODEV;
85410340e   Joerg Roedel   iommu/core: Use P...
172
  	size         = PAGE_SIZE << gfp_order;
cefc53c7f   Joerg Roedel   iommu-api: Add io...
173

409981884   Ohad Ben-Cohen   iommu/core: use t...
174
  	BUG_ON(!IS_ALIGNED(iova, size));
cefc53c7f   Joerg Roedel   iommu-api: Add io...
175

e5aa7f007   Joerg Roedel   iommu/core: Use b...
176
  	return domain->ops->unmap(domain, iova, gfp_order);
cefc53c7f   Joerg Roedel   iommu-api: Add io...
177
178
  }
  EXPORT_SYMBOL_GPL(iommu_unmap);