1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <xen/bootfdt.h>
4 #include <xen/device_tree.h>
5 #include <xen/event.h>
6 #include <xen/static-evtchn.h>
7
8 #define STATIC_EVTCHN_NODE_SIZE_CELLS 2
9
get_evtchn_dt_property(const struct dt_device_node * np,uint32_t * port,uint32_t * phandle)10 static int __init get_evtchn_dt_property(const struct dt_device_node *np,
11 uint32_t *port, uint32_t *phandle)
12 {
13 const __be32 *prop = NULL;
14 uint32_t len;
15
16 prop = dt_get_property(np, "xen,evtchn", &len);
17 if ( !prop )
18 {
19 printk(XENLOG_ERR "xen,evtchn property should not be empty.\n");
20 return -EINVAL;
21 }
22
23 if ( !len || len < dt_cells_to_size(STATIC_EVTCHN_NODE_SIZE_CELLS) )
24 {
25 printk(XENLOG_ERR "xen,evtchn property value is not valid.\n");
26 return -EINVAL;
27 }
28
29 *port = dt_next_cell(1, &prop);
30 *phandle = dt_next_cell(1, &prop);
31
32 return 0;
33 }
34
alloc_domain_evtchn(struct dt_device_node * node)35 static int __init alloc_domain_evtchn(struct dt_device_node *node)
36 {
37 int rc;
38 uint32_t domU1_port, domU2_port, remote_phandle;
39 struct dt_device_node *remote_node;
40 const struct dt_device_node *p1_node, *p2_node;
41 struct evtchn_alloc_unbound alloc_unbound;
42 struct evtchn_bind_interdomain bind_interdomain;
43 struct domain *d1 = NULL, *d2 = NULL;
44
45 if ( !dt_device_is_compatible(node, "xen,evtchn-v1") )
46 return 0;
47
48 /*
49 * Event channel is already created while parsing the other side of
50 * evtchn node.
51 */
52 if ( dt_device_static_evtchn_created(node) )
53 return 0;
54
55 rc = get_evtchn_dt_property(node, &domU1_port, &remote_phandle);
56 if ( rc )
57 return rc;
58
59 remote_node = dt_find_node_by_phandle(remote_phandle);
60 if ( !remote_node )
61 {
62 printk(XENLOG_ERR
63 "evtchn: could not find remote evtchn phandle\n");
64 return -EINVAL;
65 }
66
67 rc = get_evtchn_dt_property(remote_node, &domU2_port, &remote_phandle);
68 if ( rc )
69 return rc;
70
71 if ( node->phandle != remote_phandle )
72 {
73 printk(XENLOG_ERR "xen,evtchn property is not setup correctly.\n");
74 return -EINVAL;
75 }
76
77 p1_node = dt_get_parent(node);
78 if ( !p1_node )
79 {
80 printk(XENLOG_ERR "evtchn: evtchn parent node is NULL\n" );
81 return -EINVAL;
82 }
83
84 p2_node = dt_get_parent(remote_node);
85 if ( !p2_node )
86 {
87 printk(XENLOG_ERR "evtchn: remote parent node is NULL\n" );
88 return -EINVAL;
89 }
90
91 d1 = get_domain_by_id(p1_node->used_by);
92 d2 = get_domain_by_id(p2_node->used_by);
93
94 if ( !d1 || !d2 )
95 {
96 printk(XENLOG_ERR "evtchn: could not find domains\n" );
97 return -EINVAL;
98 }
99
100 alloc_unbound.dom = d1->domain_id;
101 alloc_unbound.remote_dom = d2->domain_id;
102
103 rc = evtchn_alloc_unbound(&alloc_unbound, domU1_port);
104 if ( rc < 0 )
105 {
106 printk(XENLOG_ERR
107 "evtchn_alloc_unbound() failure (Error %d) \n", rc);
108 return rc;
109 }
110
111 bind_interdomain.remote_dom = d1->domain_id;
112 bind_interdomain.remote_port = domU1_port;
113
114 rc = evtchn_bind_interdomain(&bind_interdomain, d2, domU2_port);
115 if ( rc < 0 )
116 {
117 printk(XENLOG_ERR
118 "evtchn_bind_interdomain() failure (Error %d) \n", rc);
119 return rc;
120 }
121
122 dt_device_set_static_evtchn_created(node);
123 dt_device_set_static_evtchn_created(remote_node);
124
125 return 0;
126 }
127
alloc_static_evtchn(void)128 void __init alloc_static_evtchn(void)
129 {
130 struct dt_device_node *node, *evtchn_node;
131 struct dt_device_node *chosen = dt_find_node_by_path("/chosen");
132
133 BUG_ON(chosen == NULL);
134
135 if ( hardware_domain )
136 dt_device_set_used_by(chosen, hardware_domain->domain_id);
137
138 dt_for_each_child_node(chosen, node)
139 {
140 if ( hardware_domain )
141 {
142 if ( alloc_domain_evtchn(node) != 0 )
143 panic("Could not set up domains evtchn\n");
144 }
145
146 dt_for_each_child_node(node, evtchn_node)
147 {
148 if ( alloc_domain_evtchn(evtchn_node) != 0 )
149 panic("Could not set up domains evtchn\n");
150 }
151 }
152 }
153
154 /*
155 * Local variables:
156 * mode: C
157 * c-file-style: "BSD"
158 * c-basic-offset: 4
159 * tab-width: 4
160 * indent-tabs-mode: nil
161 * End:
162 */
163