1 /*
2 * Code to passthrough a device tree node to a guest
3 *
4 * Julien Grall <julien.grall@linaro.org>
5 * Copyright (c) 2014 Linaro Limited.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18 #include <xen/device_tree.h>
19 #include <xen/guest_access.h>
20 #include <xen/iommu.h>
21 #include <xen/lib.h>
22 #include <xen/sched.h>
23 #include <xsm/xsm.h>
24
25 #include <asm/iommu_fwspec.h>
26
27 static spinlock_t dtdevs_lock = SPIN_LOCK_UNLOCKED;
28
iommu_assign_dt_device(struct domain * d,struct dt_device_node * dev)29 int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
30 {
31 int rc = -EBUSY;
32 struct domain_iommu *hd = dom_iommu(d);
33
34 ASSERT(system_state < SYS_STATE_active || rw_is_locked(&dt_host_lock));
35
36 if ( !is_iommu_enabled(d) )
37 return -EINVAL;
38
39 if ( !dt_device_is_protected(dev) )
40 return -EINVAL;
41
42 spin_lock(&dtdevs_lock);
43
44 if ( !list_empty(&dev->domain_list) )
45 goto fail;
46
47 /* The flag field doesn't matter to DT device. */
48 rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev), 0);
49
50 if ( rc )
51 goto fail;
52
53 list_add(&dev->domain_list, &hd->dt_devices);
54 dt_device_set_used_by(dev, d->domain_id);
55
56 fail:
57 spin_unlock(&dtdevs_lock);
58
59 return rc;
60 }
61
iommu_deassign_dt_device(struct domain * d,struct dt_device_node * dev)62 int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev)
63 {
64 const struct domain_iommu *hd = dom_iommu(d);
65 int rc;
66
67 ASSERT(rw_is_locked(&dt_host_lock));
68
69 if ( !is_iommu_enabled(d) )
70 return -EINVAL;
71
72 if ( !dt_device_is_protected(dev) )
73 return -EINVAL;
74
75 spin_lock(&dtdevs_lock);
76
77 rc = hd->platform_ops->reassign_device(d, NULL, 0, dt_to_dev(dev));
78 if ( rc )
79 goto fail;
80
81 list_del_init(&dev->domain_list);
82 dt_device_set_used_by(dev, DOMID_IO);
83
84 fail:
85 spin_unlock(&dtdevs_lock);
86
87 return rc;
88 }
89
iommu_dt_device_is_assigned_locked(const struct dt_device_node * dev)90 static bool iommu_dt_device_is_assigned_locked(const struct dt_device_node *dev)
91 {
92 bool assigned = false;
93
94 ASSERT(spin_is_locked(&dtdevs_lock));
95
96 if ( !dt_device_is_protected(dev) )
97 return 0;
98
99 assigned = !list_empty(&dev->domain_list);
100
101 return assigned;
102 }
103
iommu_dt_domain_init(struct domain * d)104 int iommu_dt_domain_init(struct domain *d)
105 {
106 INIT_LIST_HEAD(&dom_iommu(d)->dt_devices);
107
108 return 0;
109 }
110
iommu_release_dt_devices(struct domain * d)111 int iommu_release_dt_devices(struct domain *d)
112 {
113 const struct domain_iommu *hd = dom_iommu(d);
114 struct dt_device_node *dev, *_dev;
115 int rc;
116
117 if ( !is_iommu_enabled(d) )
118 return 0;
119
120 read_lock(&dt_host_lock);
121
122 list_for_each_entry_safe(dev, _dev, &hd->dt_devices, domain_list)
123 {
124 rc = iommu_deassign_dt_device(d, dev);
125 if ( rc )
126 {
127 dprintk(XENLOG_ERR, "Failed to deassign %s in domain %u\n",
128 dt_node_full_name(dev), d->domain_id);
129 read_unlock(&dt_host_lock);
130
131 return rc;
132 }
133 }
134
135 read_unlock(&dt_host_lock);
136
137 return 0;
138 }
139
iommu_remove_dt_device(struct dt_device_node * np)140 int iommu_remove_dt_device(struct dt_device_node *np)
141 {
142 const struct iommu_ops *ops = iommu_get_ops();
143 struct device *dev = dt_to_dev(np);
144 int rc;
145
146 ASSERT(rw_is_locked(&dt_host_lock));
147
148 if ( !iommu_enabled )
149 return 1;
150
151 if ( !ops )
152 return -EOPNOTSUPP;
153
154 spin_lock(&dtdevs_lock);
155
156 if ( iommu_dt_device_is_assigned_locked(np) )
157 {
158 rc = -EBUSY;
159 goto fail;
160 }
161
162 if ( !ops->remove_device )
163 {
164 rc = -EOPNOTSUPP;
165 goto fail;
166 }
167
168 /*
169 * De-register the device from the IOMMU driver.
170 * The driver is responsible for removing is_protected flag.
171 */
172 rc = ops->remove_device(0, dev);
173
174 if ( !rc )
175 {
176 ASSERT(!dt_device_is_protected(np));
177 iommu_fwspec_free(dev);
178 }
179
180 fail:
181 spin_unlock(&dtdevs_lock);
182 return rc;
183 }
184
iommu_add_dt_device(struct dt_device_node * np)185 int iommu_add_dt_device(struct dt_device_node *np)
186 {
187 const struct iommu_ops *ops = iommu_get_ops();
188 struct dt_phandle_args iommu_spec;
189 struct device *dev = dt_to_dev(np);
190 int rc = 1, index = 0;
191
192 ASSERT(system_state < SYS_STATE_active || rw_is_locked(&dt_host_lock));
193
194 if ( !iommu_enabled )
195 return 1;
196
197 if ( !ops )
198 return -EINVAL;
199
200 /*
201 * The device may already have been registered. As there is no harm in
202 * it just return success early.
203 */
204 if ( dev_iommu_fwspec_get(dev) )
205 return 0;
206
207 spin_lock(&dtdevs_lock);
208
209 /*
210 * According to the Documentation/devicetree/bindings/iommu/iommu.txt
211 * from Linux.
212 */
213 while ( !dt_parse_phandle_with_args(np, "iommus", "#iommu-cells",
214 index, &iommu_spec) )
215 {
216 /*
217 * The driver which supports generic IOMMU DT bindings must have
218 * these callback implemented.
219 */
220 if ( !ops->add_device || !ops->dt_xlate )
221 {
222 rc = -EINVAL;
223 goto fail;
224 }
225
226 if ( !dt_device_is_available(iommu_spec.np) )
227 break;
228
229 rc = iommu_fwspec_init(dev, &iommu_spec.np->dev);
230 if ( rc )
231 break;
232
233 /*
234 * Provide DT IOMMU specifier which describes the IOMMU master
235 * interfaces of that device (device IDs, etc) to the driver.
236 * The driver is responsible to decide how to interpret them.
237 */
238 rc = ops->dt_xlate(dev, &iommu_spec);
239 if ( rc )
240 break;
241
242 index++;
243 }
244
245 /*
246 * Add master device to the IOMMU if latter is present and available.
247 * The driver is responsible to mark that device as protected.
248 */
249 if ( !rc )
250 rc = ops->add_device(0, dev);
251
252 if ( rc < 0 )
253 iommu_fwspec_free(dev);
254
255 fail:
256 spin_unlock(&dtdevs_lock);
257 return rc;
258 }
259
iommu_do_dt_domctl(struct xen_domctl * domctl,struct domain * d,XEN_GUEST_HANDLE_PARAM (xen_domctl_t)u_domctl)260 int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
261 XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
262 {
263 int ret;
264 struct dt_device_node *dev;
265
266 read_lock(&dt_host_lock);
267
268 switch ( domctl->cmd )
269 {
270 case XEN_DOMCTL_assign_device:
271 ASSERT(d);
272 /* fall through */
273 case XEN_DOMCTL_test_assign_device:
274 ret = -ENODEV;
275 if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
276 break;
277
278 ret = -EINVAL;
279 if ( (d && d->is_dying) || domctl->u.assign_device.flags )
280 break;
281
282 ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
283 domctl->u.assign_device.u.dt.size,
284 &dev);
285 if ( ret )
286 break;
287
288 ret = xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
289 if ( ret )
290 break;
291
292 if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
293 {
294 spin_lock(&dtdevs_lock);
295
296 if ( iommu_dt_device_is_assigned_locked(dev) )
297 {
298 printk(XENLOG_G_ERR "%s already assigned.\n",
299 dt_node_full_name(dev));
300 ret = -EINVAL;
301 }
302
303 spin_unlock(&dtdevs_lock);
304 break;
305 }
306
307 if ( d == dom_io )
308 {
309 ret = -EINVAL;
310 break;
311 }
312
313 ret = iommu_add_dt_device(dev);
314 if ( ret < 0 )
315 {
316 printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
317 dt_node_full_name(dev));
318 break;
319 }
320
321 ret = iommu_assign_dt_device(d, dev);
322
323 if ( ret )
324 printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
325 " to dom%u failed (%d)\n",
326 dt_node_full_name(dev), d->domain_id, ret);
327 break;
328
329 case XEN_DOMCTL_deassign_device:
330 ret = -ENODEV;
331 if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
332 break;
333
334 ret = -EINVAL;
335 if ( domctl->u.assign_device.flags )
336 break;
337
338 ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
339 domctl->u.assign_device.u.dt.size,
340 &dev);
341 if ( ret )
342 break;
343
344 ret = xsm_deassign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
345 if ( ret )
346 break;
347
348 if ( d == dom_io )
349 {
350 ret = -EINVAL;
351 break;
352 }
353
354 ret = iommu_deassign_dt_device(d, dev);
355
356 if ( ret )
357 printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
358 " to dom%u failed (%d)\n",
359 dt_node_full_name(dev), d->domain_id, ret);
360 break;
361
362 default:
363 ret = -ENOSYS;
364 break;
365 }
366
367 read_unlock(&dt_host_lock);
368
369 return ret;
370 }
371