This will reserve a 512MB region starting at the host physical address
0x30000000 to be exclusively used by DomU1.
+
+Static Event Channel
+====================
+The event channel communication will be established statically between two
+domains (dom0 and domU also). Event channel connection information between
+domains will be passed to Xen via the device tree node. The event channel
+will be created and established in Xen before the domain started. The domain
+does not need to do any operation to establish a connection. Domain only
+needs hypercall EVTCHNOP_send(local port) to send notifications to the
+remote guest.
+
+There is no need to describe the static event channel info in the domU device
+tree. Static event channels are only useful in fully static configurations,
+and in those configurations, the domU device tree dynamically generated by Xen
+is not needed.
+
+To enable the event-channel interface for domU guests include the
+xen,enhanced = "no-xenstore" property in the domU Xen device tree node.
+
+Under the "xen,domain" compatible node for domU, there needs to be sub-nodes
+with compatible "xen,evtchn" that describe the event channel connection
+between two domUs. For dom0, there needs to be sub-nodes with compatible
+"xen,evtchn" under the chosen node.
+
+The static event channel node has the following properties:
+
+- compatible
+
+ "xen,evtchn"
+
+- xen,evtchn
+
+ The property is tuples of two numbers
+ (local-evtchn link-to-foreign-evtchn) where:
+
+ local-evtchn is an integer value that will be used to allocate local port
+ for a domain to send and receive event notifications to/from the remote
+ domain. Maximum supported value is 2^17 for FIFO ABI and 4096 for 2L ABI.
+ It is recommended to use low event channel IDs.
+
+ link-to-foreign-evtchn is a single phandle to a remote evtchn to which
+ local-evtchn will be connected.
+
+Example
+=======
+
+chosen {
+
+ /* One sub-node per local event channel. This sub-node is for Dom0. */
+ ec1: evtchn@1 {
+ compatible = "xen,evtchn-v1";
+ /* local-evtchn link-to-foreign-evtchn */
+ xen,evtchn = <0xa &ec2>;
+ };
+
+ domU1 {
+ compatible = "xen,domain";
+ #address-cells = <0x2>;
+ #size-cells = <0x1>;
+ xen,enhanced = "no-xenstore";
+
+ /* One sub-node per local event channel */
+ ec2: evtchn@2 {
+ compatible = "xen,evtchn-v1";
+ /* local-evtchn link-to-foreign-evtchn */
+ xen,evtchn = <0xa &ec1>;
+ };
+
+ ec3: evtchn@3 {
+ compatible = "xen,evtchn-v1";
+ xen,evtchn = <0xb &ec5>;
+ };
+
+ ec4: evtchn@4 {
+ compatible = "xen,evtchn-v1";
+ xen,evtchn = <0xc &ec6>;
+ };
+ };
+
+ domU2 {
+ compatible = "xen,domain";
+ #address-cells = <0x2>;
+ #size-cells = <0x1>;
+ xen,enhanced = "no-xenstore";
+
+ /* One sub-node per local event channel */
+ ec5: evtchn@5 {
+ compatible = "xen,evtchn-v1";
+ /* local-evtchn link-to-foreign-evtchn */
+ xen,evtchn = <0xb &ec3>;
+ };
+
+ ec6: evtchn@6 {
+ compatible = "xen,evtchn-v1";
+ xen,evtchn = <0xd &ec4>;
+ };
+ };
+};
#include <xen/grant_table.h>
#include <xen/serial.h>
+#define STATIC_EVTCHN_NODE_SIZE_CELLS 2
+
static unsigned int __initdata opt_dom0_max_vcpus;
integer_param("dom0_max_vcpus", opt_dom0_max_vcpus);
d->arch.hvm.params[HVM_PARAM_CALLBACK_IRQ] = val;
}
+static int __init get_evtchn_dt_property(const struct dt_device_node *np,
+ uint32_t *port, uint32_t *phandle)
+{
+ const __be32 *prop = NULL;
+ uint32_t len;
+
+ prop = dt_get_property(np, "xen,evtchn", &len);
+ if ( !prop )
+ {
+ printk(XENLOG_ERR "xen,evtchn property should not be empty.\n");
+ return -EINVAL;
+ }
+
+ if ( !len || len < dt_cells_to_size(STATIC_EVTCHN_NODE_SIZE_CELLS) )
+ {
+ printk(XENLOG_ERR "xen,evtchn property value is not valid.\n");
+ return -EINVAL;
+ }
+
+ *port = dt_next_cell(1, &prop);
+ *phandle = dt_next_cell(1, &prop);
+
+ return 0;
+}
+
+static int __init alloc_domain_evtchn(struct dt_device_node *node)
+{
+ int rc;
+ uint32_t domU1_port, domU2_port, remote_phandle;
+ struct dt_device_node *remote_node;
+ const struct dt_device_node *p1_node, *p2_node;
+ struct evtchn_alloc_unbound alloc_unbound;
+ struct evtchn_bind_interdomain bind_interdomain;
+ struct domain *d1 = NULL, *d2 = NULL;
+
+ if ( !dt_device_is_compatible(node, "xen,evtchn-v1") )
+ return 0;
+
+ /*
+ * Event channel is already created while parsing the other side of
+ * evtchn node.
+ */
+ if ( dt_device_static_evtchn_created(node) )
+ return 0;
+
+ rc = get_evtchn_dt_property(node, &domU1_port, &remote_phandle);
+ if ( rc )
+ return rc;
+
+ remote_node = dt_find_node_by_phandle(remote_phandle);
+ if ( !remote_node )
+ {
+ printk(XENLOG_ERR
+ "evtchn: could not find remote evtchn phandle\n");
+ return -EINVAL;
+ }
+
+ rc = get_evtchn_dt_property(remote_node, &domU2_port, &remote_phandle);
+ if ( rc )
+ return rc;
+
+ if ( node->phandle != remote_phandle )
+ {
+ printk(XENLOG_ERR "xen,evtchn property is not setup correctly.\n");
+ return -EINVAL;
+ }
+
+ p1_node = dt_get_parent(node);
+ if ( !p1_node )
+ {
+ printk(XENLOG_ERR "evtchn: evtchn parent node is NULL\n" );
+ return -EINVAL;
+ }
+
+ p2_node = dt_get_parent(remote_node);
+ if ( !p2_node )
+ {
+ printk(XENLOG_ERR "evtchn: remote parent node is NULL\n" );
+ return -EINVAL;
+ }
+
+ d1 = get_domain_by_id(p1_node->used_by);
+ d2 = get_domain_by_id(p2_node->used_by);
+
+ if ( !d1 || !d2 )
+ {
+ printk(XENLOG_ERR "evtchn: could not find domains\n" );
+ return -EINVAL;
+ }
+
+ alloc_unbound.dom = d1->domain_id;
+ alloc_unbound.remote_dom = d2->domain_id;
+
+ rc = evtchn_alloc_unbound(&alloc_unbound, domU1_port);
+ if ( rc < 0 )
+ {
+ printk(XENLOG_ERR
+ "evtchn_alloc_unbound() failure (Error %d) \n", rc);
+ return rc;
+ }
+
+ bind_interdomain.remote_dom = d1->domain_id;
+ bind_interdomain.remote_port = domU1_port;
+
+ rc = evtchn_bind_interdomain(&bind_interdomain, d2, domU2_port);
+ if ( rc < 0 )
+ {
+ printk(XENLOG_ERR
+ "evtchn_bind_interdomain() failure (Error %d) \n", rc);
+ return rc;
+ }
+
+ dt_device_set_static_evtchn_created(node);
+ dt_device_set_static_evtchn_created(remote_node);
+
+ return 0;
+}
+
+void __init alloc_static_evtchn(void)
+{
+ struct dt_device_node *node, *evtchn_node;
+ struct dt_device_node *chosen = dt_find_node_by_path("/chosen");
+
+ BUG_ON(chosen == NULL);
+
+ if ( hardware_domain )
+ dt_device_set_used_by(chosen, hardware_domain->domain_id);
+
+ dt_for_each_child_node(chosen, node)
+ {
+ if ( hardware_domain )
+ {
+ if ( alloc_domain_evtchn(node) != 0 )
+ panic("Could not set up domains evtchn\n");
+ }
+
+ dt_for_each_child_node(node, evtchn_node)
+ {
+ if ( alloc_domain_evtchn(evtchn_node) != 0 )
+ panic("Could not set up domains evtchn\n");
+ }
+ }
+}
+
static void __init find_gnttab_region(struct domain *d,
struct kernel_info *kinfo)
{
panic("Error creating domain %s\n", dt_node_name(node));
d->is_console = true;
+ dt_device_set_used_by(node, d->domain_id);
if ( construct_domU(d, node) != 0 )
panic("Could not set up domain %s\n", dt_node_name(node));