1 /*
2 * Generic IOMMU framework via the device tree
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/iommu.h>
20 #include <xen/lib.h>
21
22 #include <asm/device.h>
23
24 /*
25 * Deferred probe list is used to keep track of devices for which driver
26 * requested deferred probing (returned -EAGAIN).
27 */
28 static __initdata LIST_HEAD(deferred_probe_list);
29
30 static const struct iommu_ops *iommu_ops;
31
iommu_get_ops(void)32 const struct iommu_ops *iommu_get_ops(void)
33 {
34 return iommu_ops;
35 }
36
iommu_set_ops(const struct iommu_ops * ops)37 void __init iommu_set_ops(const struct iommu_ops *ops)
38 {
39 BUG_ON(ops == NULL);
40
41 if ( iommu_ops && iommu_ops != ops )
42 {
43 printk("WARNING: Cannot set IOMMU ops, already set to a different value\n");
44 return;
45 }
46
47 iommu_ops = ops;
48 }
49
iommu_hardware_setup(void)50 int __init iommu_hardware_setup(void)
51 {
52 struct dt_device_node *np, *tmp;
53 int rc;
54 unsigned int num_iommus = 0;
55
56 dt_for_each_device_node(dt_host, np)
57 {
58 rc = device_init(np, DEVICE_IOMMU, NULL);
59 if ( !rc )
60 num_iommus++;
61 else if ( rc == -EAGAIN )
62 {
63 /*
64 * Nobody should use device's domain_list at such early stage,
65 * so we can re-use it to link the device in the deferred list to
66 * avoid introducing extra list_head field in struct dt_device_node.
67 */
68 ASSERT(list_empty(&np->domain_list));
69
70 /*
71 * Driver requested deferred probing, so add this device to
72 * the deferred list for further processing.
73 */
74 list_add(&np->domain_list, &deferred_probe_list);
75 }
76 /*
77 * Ignore the following error codes:
78 * - EBADF: Indicate the current is not an IOMMU
79 * - ENODEV: The IOMMU is not present or cannot be used by
80 * Xen.
81 */
82 else if ( rc != -EBADF && rc != -ENODEV )
83 return rc;
84 }
85
86 /* Return immediately if there are no initialized devices. */
87 if ( !num_iommus )
88 return list_empty(&deferred_probe_list) ? -ENODEV : -EAGAIN;
89
90 rc = 0;
91
92 /*
93 * Process devices in the deferred list if it is not empty.
94 * Check that at least one device is initialized at each loop, otherwise
95 * we may get an infinite loop. Also stop processing if we got an error
96 * other than -EAGAIN.
97 */
98 while ( !list_empty(&deferred_probe_list) && num_iommus )
99 {
100 num_iommus = 0;
101
102 list_for_each_entry_safe ( np, tmp, &deferred_probe_list, domain_list )
103 {
104 rc = device_init(np, DEVICE_IOMMU, NULL);
105 if ( !rc )
106 {
107 num_iommus++;
108
109 /* Remove initialized device from the deferred list. */
110 list_del_init(&np->domain_list);
111 }
112 else if ( rc != -EAGAIN )
113 return rc;
114 }
115 }
116
117 return rc;
118 }
119
arch_iommu_check_autotranslated_hwdom(struct domain * d)120 void __hwdom_init arch_iommu_check_autotranslated_hwdom(struct domain *d)
121 {
122 /* ARM doesn't require specific check for hwdom */
123 return;
124 }
125
arch_iommu_domain_init(struct domain * d)126 int arch_iommu_domain_init(struct domain *d)
127 {
128 return iommu_dt_domain_init(d);
129 }
130
arch_iommu_domain_destroy(struct domain * d)131 void arch_iommu_domain_destroy(struct domain *d)
132 {
133 }
134
arch_iommu_hwdom_init(struct domain * d)135 void __hwdom_init arch_iommu_hwdom_init(struct domain *d)
136 {
137 }
138