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