From: harry <harry@hebutterworth.freeserve.co.uk>
To: xen-devel@lists.xensource.com
Subject: [PATCH][8/17] USB virt 2.6 split driver---xbgt channel
Date: Mon, 21 Nov 2005 13:19:02 +0000 [thread overview]
Message-ID: <1132579142.31295.119.camel@localhost.localdomain> (raw)
[-- Attachment #1: Type: text/plain, Size: 399 bytes --]
This patch implements the xenidc_xbgt_channel or xenbus grant-table
channel which is an interdomain message channel based on grant-tables
(this bit implemented by composition using a xenidc_gnttab_channel from
a previous patch) with bring up and tear down implemented using xenbus
(this bit implemented in this patch by xenidc_xbgt_channel).
Signed-off-by: Harry Butterworth <butterwo@uk.ibm.com>
[-- Attachment #2: p8-xbgt-channel.patch --]
[-- Type: text/x-patch, Size: 63290 bytes --]
diff -r 47edf571a62d -r 1786d40e66b8 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Sun Nov 20 17:44:51 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Sun Nov 20 17:45:04 2005
@@ -11,3 +11,4 @@
xenidc-objs += xenidc_grant_table.o
xenidc-objs += xenidc_vaddress.o
xenidc-objs += xenidc_gnttab_channel.o
+xenidc-objs += xenidc_xbgt_channel.o
diff -r 47edf571a62d -r 1786d40e66b8 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c
--- /dev/null Sun Nov 20 17:44:51 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c Sun Nov 20 17:45:04 2005
@@ -0,0 +1,1607 @@
+/*****************************************************************************/
+/* This is a class which uses a xenidc_gnttab_channel (grant-tables based */
+/* message channel class) and xenbus to implement an interdomain message */
+/* channel with grant-tables based message transfer and xenbus based */
+/* bring-up and tear-down handshaking. */
+/* This class is used in the implementation of the xenidc_endpoint class. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* The state machine below makes the following assumptions: */
+/* */
+/* 1) The store might contain some stale cruft from the last time our device */
+/* driver failed. This is a handy assumption for testing new versions of */
+/* the driver but isn't strictly necessary. */
+/* */
+/* 2) If the other side generates a protocol error on the inter-domain */
+/* connection then we attempt to disconnect and reconnect. An alternative */
+/* behaviour would be to wait for our interface to be called to disconnect */
+/* and then reconnect before retrying. */
+/* */
+/* 3) If we experience an internal failure (fail to register watch for */
+/* example) then we attempt to disconnect and wait for our interface to be */
+/* called to disconnect (by module unload for example) and reconnect before */
+/* retrying. */
+/* */
+/* 4) Connection and disconnection of the channel is done in two phases: the */
+/* first phase makes the local resources available to the remote side, the */
+/* second phase uses the resources of the remote side to complete the */
+/* connection. */
+/* */
+/* The key for the stimuli is as follows: */
+/* */
+/* cn: interface called to connect the channel when interface state is */
+/* disconnected (for example on module load). */
+/* */
+/* pe: protocol error detected when channel is in a state between phase two */
+/* connected and the completion of the phase two disconnect callback. */
+/* */
+/* dn: interface called to disconnect the channel when the interface state */
+/* is connected (for example on module unload). */
+/* */
+/* ou: a synchronous stimulus from the response test_other_state which */
+/* indicates that the other state is still unknown because the watch */
+/* callback hasn't happened yet. Can only happen when making the response */
+/* test_other_state. */
+/* */
+/* od: other state is disconnected. This is both a synchronous stimulus */
+/* from test_other_state and an asynchronous stimulus from the watch */
+/* function. Disconnected means that we can't read at least the other side's */
+/* ready node from the store. */
+/* */
+/* or: other state is ready. This is both a synchronous stimulus from */
+/* test_other_state and an asynchronous stimulus from the watch function. */
+/* Ready means that we can see the other side's ready node but not the */
+/* ring-reference and event-channel information. */
+/* */
+/* oc: other state is connected. This is both a synchronous stimulus from */
+/* test_other_state and an asynchronous stimulus from the watch function. */
+/* Connected means that we found both the ready node and the connected */
+/* information in the store. */
+/* */
+/* If the values of the connected information change when the other side is */
+/* connected then we generate the 'oc' stimulus again which forces a */
+/* reconnect. */
+/* */
+/* rs: An asynchronous response was successful (we only make one response at */
+/* a time so all asynchronous responses have the same completion stimuli). */
+/* */
+/* rf: An asynchronous response failed. Only register_watch, clear_store, */
+/* write_ready, write_connected, phase_two_connect can fail. Only */
+/* phase_two_connect has a good reason for failure: the other side might */
+/* have passed bogus parameters; the other failures are poor API design and */
+/* ought to be promoted to domain failures. */
+/* */
+/* The state machine responses are as follows: */
+/* */
+/* test_other_state: what state do we currently think the other side is in */
+/* as reflected by the last watch event. Synchronous (called with the lock */
+/* held) completes with ou/od/or/oc. */
+/* */
+/* register_watch: register a watch on the other side. */
+/* */
+/* unregister_watch: unregister the watch. */
+/* */
+/* clear_store: remove the ready node and connected information. */
+/* */
+/* write_ready: write the ready node to the store. */
+/* */
+/* write_connected: write the connected information to the store. */
+/* */
+/* phase_one_connect: grant the remote side access to the local page etc. */
+/* */
+/* phase_two_connect: map the remote page etc. */
+/* */
+/* phase_two_disconnect: unmap the remote page. */
+/* */
+/* phase_one_disconnect: revoke the access of the remote side. */
+/* */
+/* complete_disconnect: When our interface is called to get us to disconnect */
+/* the channel we quiesce and disconnect and then call this to indicate we */
+/* are done. */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc_xbgt_channel.h>
+#include <linux/err.h>
+#include "xenidc_trace.h"
+
+typedef enum {
+ xenidc_xbgt_channel_stimulus_cn, /* Connect: disconnected */
+ xenidc_xbgt_channel_stimulus_pe, /* Protocol error: ph2c->ph2dc inclusive */
+ xenidc_xbgt_channel_stimulus_dn, /* Disconnect: connected */
+ xenidc_xbgt_channel_stimulus_ou, /* Other unknown: test other state only */
+ xenidc_xbgt_channel_stimulus_od, /* Other disconnected: watch / test */
+ xenidc_xbgt_channel_stimulus_or, /* Other ready: watch / test */
+ xenidc_xbgt_channel_stimulus_oc, /* Other connected: watch / test */
+ xenidc_xbgt_channel_stimulus_rs, /* Response successful: making response */
+ xenidc_xbgt_channel_stimulus_rf /* Response failed: r. watch, tra, ph2c */
+} xenidc_xbgt_channel_stimulus;
+
+static void xenidc_xbgt_channel_handle_stimulus
+ (xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus);
+
+static int xenidc_xbgt_channel_init_or_exit
+ (xenidc_xbgt_channel * channel, int exit);
+
+int xenidc_xbgt_channel_init(xenidc_xbgt_channel * channel)
+{
+ return xenidc_xbgt_channel_init_or_exit(channel, 0);
+}
+
+void xenidc_xbgt_channel_connect
+ (xenidc_xbgt_channel * channel,
+ const char *local_path,
+ const char *remote_path, domid_t remote_domain_id) {
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ channel->local_path = local_path;
+ channel->remote_path = remote_path;
+ channel->remote_domain_id = remote_domain_id;
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_cn);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+}
+
+static void xenidc_xbgt_channel_watch
+ (struct xenbus_watch *watch, const char **vec, unsigned int len) {
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel =
+ container_of(watch, xenidc_xbgt_channel, watch);
+
+ struct xenbus_transaction *transaction =
+ xenbus_transaction_start();
+
+ if (IS_ERR(transaction)) {
+ trace0("error starting transaction");
+
+ goto DISCONNECTED;
+ }
+
+ {
+ unsigned int event_channel;
+ unsigned int ring_reference;
+ unsigned int ready;
+
+ int error = xenbus_gather(transaction,
+ watch->node,
+ "ready", "%u", &ready,
+ "event-channel", "%u",
+ &event_channel,
+ "ring-reference", "%u",
+ &ring_reference,
+ NULL);
+
+ if (error == 0) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ if ((channel->other_state
+ !=
+ xenidc_xbgt_channel_other_state_connected)
+ ||
+ (channel->ready_event_channel !=
+ event_channel)
+ || (channel->ready_ring_reference !=
+ ring_reference)
+ ) {
+ channel->other_state =
+ xenidc_xbgt_channel_other_state_connected;
+
+ channel->ready_event_channel =
+ event_channel;
+ channel->ready_ring_reference =
+ ring_reference;
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel,
+ xenidc_xbgt_channel_stimulus_oc);
+ }
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+
+ xenbus_transaction_end(transaction,
+ 1 /* abort */ );
+
+ return;
+ }
+ }
+
+ {
+ unsigned int ready;
+
+ int error = xenbus_gather(transaction,
+ watch->node,
+ "ready", "%u", &ready,
+ NULL);
+
+ if (error == 0) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ if ((channel->other_state
+ != xenidc_xbgt_channel_other_state_ready)
+ ) {
+ channel->other_state =
+ xenidc_xbgt_channel_other_state_ready;
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel,
+ xenidc_xbgt_channel_stimulus_or);
+ }
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+
+ xenbus_transaction_end(transaction,
+ 1 /* abort */ );
+
+ return;
+ }
+ }
+
+ xenbus_transaction_end(transaction, 1 /* abort */ );
+
+ DISCONNECTED:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ if (channel->other_state
+ != xenidc_xbgt_channel_other_state_disconnected) {
+ channel->other_state =
+ xenidc_xbgt_channel_other_state_disconnected;
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_od);
+ }
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_protocol_error
+ (xenidc_gnttab_channel * gnttab_channel) {
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel =
+ xenidc_xbgt_channel_gnttab_channel_to(gnttab_channel);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_pe);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+}
+
+void xenidc_xbgt_channel_disconnect
+ (xenidc_xbgt_channel * channel, xenidc_callback * callback) {
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ channel->disconnect_callback = callback;
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_dn);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+}
+
+void xenidc_xbgt_channel_exit(xenidc_xbgt_channel * channel)
+{
+ trace();
+
+ (void)xenidc_xbgt_channel_init_or_exit(channel, 1);
+}
+
+static void xenidc_xbgt_channel_register_watch_1(void *data);
+static void xenidc_xbgt_channel_unregister_watch_1(void *data);
+static void xenidc_xbgt_channel_clear_store_1(void *data);
+static void xenidc_xbgt_channel_write_ready_1(void *data);
+static void xenidc_xbgt_channel_write_connected_1(void *data);
+static void xenidc_xbgt_channel_phase_one_connect_1(void *data);
+static void xenidc_xbgt_channel_phase_one_connect_2(xenidc_callback * callback);
+static void xenidc_xbgt_channel_phase_two_connect_1(void *data);
+static void xenidc_xbgt_channel_phase_two_connect_2(xenidc_callback * callback);
+static void xenidc_xbgt_channel_phase_two_disconnect_1(void *data);
+static void xenidc_xbgt_channel_phase_two_disconnect_2
+ (xenidc_callback * callback);
+static void xenidc_xbgt_channel_phase_one_disconnect_1(void *data);
+static void xenidc_xbgt_channel_phase_one_disconnect_2
+ (xenidc_callback * callback);
+
+static int xenidc_xbgt_channel_init_or_exit
+ (xenidc_xbgt_channel * channel, int exit) {
+ trace();
+
+ {
+ int return_value = 0;
+
+ if (exit) {
+ goto EXIT;
+ }
+
+ if ((return_value = xenidc_gnttab_channel_init
+ (&channel->channel, xenidc_xbgt_channel_protocol_error)
+ )
+ != 0) {
+ goto EXIT_NO_GNTTAB_CHANNEL;
+ }
+
+ spin_lock_init(&channel->lock);
+
+ channel->state = xenidc_xbgt_channel_state_i;
+
+ xenidc_work_init
+ (&channel->register_watch_1_work,
+ xenidc_xbgt_channel_register_watch_1, channel);
+
+ xenidc_work_init
+ (&channel->unregister_watch_1_work,
+ xenidc_xbgt_channel_unregister_watch_1, channel);
+
+ xenidc_work_init
+ (&channel->clear_store_1_work,
+ xenidc_xbgt_channel_clear_store_1, channel);
+
+ xenidc_work_init
+ (&channel->write_ready_1_work,
+ xenidc_xbgt_channel_write_ready_1, channel);
+
+ xenidc_work_init
+ (&channel->write_connected_1_work,
+ xenidc_xbgt_channel_write_connected_1, channel);
+
+ xenidc_work_init
+ (&channel->phase_one_connect_1_work,
+ xenidc_xbgt_channel_phase_one_connect_1, channel);
+
+ xenidc_work_init
+ (&channel->phase_two_connect_1_work,
+ xenidc_xbgt_channel_phase_two_connect_1, channel);
+
+ xenidc_work_init
+ (&channel->phase_two_disconnect_1_work,
+ xenidc_xbgt_channel_phase_two_disconnect_1, channel);
+
+ xenidc_work_init
+ (&channel->phase_one_disconnect_1_work,
+ xenidc_xbgt_channel_phase_one_disconnect_1, channel);
+
+ xenidc_callback_init
+ (&channel->phase_one_connect_request.callback,
+ xenidc_xbgt_channel_phase_one_connect_2);
+
+ xenidc_callback_init
+ (&channel->phase_two_connect_request.callback,
+ xenidc_xbgt_channel_phase_two_connect_2);
+
+ xenidc_callback_init
+ (&channel->phase_two_disconnect_callback,
+ xenidc_xbgt_channel_phase_two_disconnect_2);
+
+ xenidc_callback_init
+ (&channel->phase_one_disconnect_callback,
+ xenidc_xbgt_channel_phase_one_disconnect_2);
+
+ return 0;
+
+ EXIT:
+
+ xenidc_gnttab_channel_exit(&channel->channel);
+
+ EXIT_NO_GNTTAB_CHANNEL:
+
+ return return_value;
+ }
+}
+
+static void xenidc_xbgt_channel_invalid_stimulus
+ (xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus);
+
+static void xenidc_xbgt_channel_test_other_state(xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_register_watch(xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_unregister_watch(xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_clear_store(xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_write_ready(xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_write_connected(xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_phase_one_connect
+ (xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_phase_two_connect
+ (xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_phase_two_disconnect
+ (xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_phase_one_disconnect
+ (xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_complete_disconnect
+ (xenidc_xbgt_channel * channel);
+
+static void xenidc_xbgt_channel_handle_stimulus
+ (xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus) {
+ trace3
+ ("xbgt channel %p in state %d received stimulus %d",
+ channel, channel->state, stimulus);
+
+ switch (channel->state) {
+ case xenidc_xbgt_channel_state_i:
+ /* Interface disconnected. */
+ /* Gnttab channel disconnected. */
+ /* Local store unknown. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_cn:
+ channel->state = xenidc_xbgt_channel_state_i_cn;
+ xenidc_xbgt_channel_phase_one_connect(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn:
+ /* Interface connected. */
+ /* Gnttab channel phase one connecting. */
+ /* Local store unknown. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_register_watch(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connecting */
+ /* Local store unknown. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected and registering watch or */
+ /* Watch registered and gnttab channel phase two disconnecting */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_pe:
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_dn_rs:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected */
+ /* Clearing store. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_rs:
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_dn_rs_rs;
+ xenidc_xbgt_channel_phase_one_disconnect(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected. */
+ /* Local store unknown. */
+ /* Registering watch. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Clearing Store. */
+ /* Watch Registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs;
+ xenidc_xbgt_channel_test_other_state(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rf:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Clearing store. */
+ /* Something failed. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rf_rs;
+ xenidc_xbgt_channel_phase_one_disconnect(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_dn_rs_rs:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one disconnecting */
+ /* Attempted to clear store. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i;
+ xenidc_xbgt_channel_complete_disconnect(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_dn_rs:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected. */
+ /* Local store unknown. */
+ /* Unregistering watch. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected unless ph2 disconnecting below. */
+ /* Clearing Store / writing ready / writing connected / ... */
+ /* ... ph2 disconnecting */
+ /* Watch Registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_pe:
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Store clear. */
+ /* Watch Registered. */
+ /* Testing other state / other state unknown/connected */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_ou:
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od;
+ xenidc_xbgt_channel_write_ready(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rf:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Unregistering watch. */
+ /* Something failed. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rf_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one disconnecting. */
+ /* Attempted to clear store. */
+ /* Something failed. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_dn_rs_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs;
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Writing Ready. */
+ /* Watch Registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs;
+ xenidc_xbgt_channel_test_other_state(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one disconnected. */
+ /* Attempted to clear store. */
+ /* Something failed. */
+ /* Watch not registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i;
+ xenidc_xbgt_channel_complete_disconnect(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Ready. */
+ /* Watch registered. */
+ /* Testing other state or other state disconnected */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ break;
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or;
+ xenidc_xbgt_channel_write_connected(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Writing Connected. */
+ /* Watch registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs;
+ xenidc_xbgt_channel_test_other_state(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Testing other state / other state ready. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_or:
+ break;
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc;
+ xenidc_xbgt_channel_phase_two_connect(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc:
+ /* Interface connected. */
+ /* Gnttab channel phase two connecting. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Other side connected. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_pe:
+ /* Phase two disconnect then go around. */
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe;
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ /* Maybe we picked up stale state from the store. Go around. */
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe:
+ /* Interface connected. */
+ /* Gnttab channel phase two connecting. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Protocol error or glitch. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_pe:
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_phase_two_disconnect(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase two connecting. */
+ /* Connected. */
+ /* Watch registered. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_pe:
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ xenidc_xbgt_channel_phase_two_disconnect(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase two connected. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Other side connected. */
+ /* Totally happy. */
+ switch (stimulus) {
+ case xenidc_xbgt_channel_stimulus_pe:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_phase_two_disconnect(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ xenidc_xbgt_channel_phase_two_disconnect(channel);
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_phase_two_disconnect(channel);
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus(channel, stimulus);
+ break;
+ }
+}
+
+static void xenidc_xbgt_channel_invalid_stimulus
+ (xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus) {
+ trace();
+
+ printk
+ (KERN_ERR "xenidc: xbgt channel %p in state %d"
+ "received invalid stimulus %d", channel, channel->state, stimulus);
+}
+
+static void xenidc_xbgt_channel_test_other_state(xenidc_xbgt_channel * channel) {
+ trace();
+
+ switch (channel->other_state) {
+ case xenidc_xbgt_channel_other_state_unknown:
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_ou);
+ break;
+ case xenidc_xbgt_channel_other_state_disconnected:
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_od);
+ break;
+ case xenidc_xbgt_channel_other_state_ready:
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_or);
+ break;
+ case xenidc_xbgt_channel_other_state_connected:
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_oc);
+ break;
+ }
+}
+
+static void xenidc_xbgt_channel_register_watch(xenidc_xbgt_channel * channel) {
+ trace();
+
+ channel->other_state = xenidc_xbgt_channel_other_state_unknown;
+
+ (void)xenidc_work_schedule(&channel->register_watch_1_work);
+}
+
+static void xenidc_xbgt_channel_register_watch_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ channel->watch.node = channel->remote_path;
+ channel->watch.callback = xenidc_xbgt_channel_watch;
+
+ {
+ int return_value =
+ register_xenbus_watch(&channel->watch);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ if (return_value == 0) {
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+ } else {
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rf);
+ }
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_unregister_watch(xenidc_xbgt_channel * channel) {
+ trace();
+
+ (void)xenidc_work_schedule(&channel->unregister_watch_1_work);
+}
+
+static void xenidc_xbgt_channel_unregister_watch_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ unregister_xenbus_watch(&channel->watch);
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_clear_store(xenidc_xbgt_channel * channel)
+{
+ trace();
+
+ (void)xenidc_work_schedule(&channel->clear_store_1_work);
+}
+
+static void xenidc_xbgt_channel_clear_store_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ struct xenbus_transaction *transaction;
+
+ AGAIN:
+
+ transaction = xenbus_transaction_start();
+
+ if (IS_ERR(transaction)) {
+ trace0("error starting transaction");
+
+ goto ERROR;
+ }
+
+ {
+ int error =
+ xenbus_rm(transaction, channel->local_path,
+ "ready");
+
+ if (error) {
+ trace0("error removing ready field from store");
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error =
+ xenbus_rm(transaction, channel->local_path,
+ "event-channel");
+
+ if (error) {
+ trace0
+ ("error removing event-channel field from store");
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error =
+ xenbus_rm(transaction, channel->local_path,
+ "ring-reference");
+
+ if (error) {
+ trace0
+ ("error removing ring-reference field from store");
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error =
+ xenbus_transaction_end(transaction,
+ 0 /* commit */ );
+
+ if (error != 0) {
+ if (error == -EAGAIN) {
+ goto AGAIN;
+ } else {
+ trace0("error committing transaction");
+
+ goto ERROR;
+ }
+ }
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+
+ return;
+
+ ABORT_TRANSACTION:
+
+ xenbus_transaction_end(transaction, 1 /* abort */ );
+
+ ERROR:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rf);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_write_ready(xenidc_xbgt_channel * channel)
+{
+ trace();
+
+ (void)xenidc_work_schedule(&channel->write_ready_1_work);
+}
+
+static void xenidc_xbgt_channel_write_ready_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ struct xenbus_transaction *transaction;
+
+ AGAIN:
+
+ transaction = xenbus_transaction_start();
+
+ if (IS_ERR(transaction)) {
+ trace0("error starting transaction");
+
+ goto ERROR;
+ }
+
+ {
+ int error = xenbus_write(transaction,
+ channel->local_path,
+ "ready",
+ "1");
+
+ if (error) {
+ trace0("error writing ready to store");
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error =
+ xenbus_transaction_end(transaction,
+ 0 /* commit */ );
+
+ if (error != 0) {
+ if (error == -EAGAIN) {
+ goto AGAIN;
+ } else {
+ trace0("error committing transaction");
+
+ goto ERROR;
+ }
+ }
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+
+ return;
+
+ ABORT_TRANSACTION:
+
+ xenbus_transaction_end(transaction, 1 /* abort */ );
+
+ ERROR:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rf);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_write_connected(xenidc_xbgt_channel * channel) {
+ trace();
+
+ (void)xenidc_work_schedule(&channel->write_connected_1_work);
+}
+
+static void xenidc_xbgt_channel_write_connected_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ struct xenbus_transaction *transaction;
+
+ xenidc_gnttab_channel_reset_ring(&channel->channel);
+
+ AGAIN:
+
+ transaction = xenbus_transaction_start();
+
+ if (IS_ERR(transaction)) {
+ trace0("error starting transaction");
+
+ goto ERROR;
+ }
+
+ {
+ int error = xenbus_printf(transaction,
+ channel->local_path,
+ "ring-reference",
+ "%u",
+ channel->
+ phase_one_connect_request.
+ send_ring_ref);
+
+ if (error) {
+ trace0("error writing ring-reference to store");
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_printf(transaction,
+ channel->local_path,
+ "event-channel",
+ "%u",
+ channel->
+ phase_one_connect_request.
+ send_event_channel);
+
+ if (error) {
+ trace0("error writing event-channel to store");
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error =
+ xenbus_transaction_end(transaction,
+ 0 /* commit */ );
+
+ if (error != 0) {
+ if (error == -EAGAIN) {
+ goto AGAIN;
+ } else {
+ trace0("error committing transaction");
+
+ goto ERROR;
+ }
+ }
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+
+ return;
+
+ ABORT_TRANSACTION:
+
+ xenbus_transaction_end(transaction, 1 /* abort */ );
+
+ ERROR:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rf);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_connect(xenidc_xbgt_channel * channel) {
+ trace();
+
+ channel->phase_one_connect_request.remote_domain_id =
+ channel->remote_domain_id;
+
+ (void)xenidc_work_schedule(&channel->phase_one_connect_1_work);
+}
+
+static void xenidc_xbgt_channel_phase_one_connect_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ xenidc_gnttab_channel_phase_one_connect
+ (&channel->channel, &channel->phase_one_connect_request);
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_connect_2(xenidc_callback * callback) {
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = container_of
+ (xenidc_gnttab_channel_phase_one_connect_request_callback_to
+ (callback),
+ xenidc_xbgt_channel,
+ phase_one_connect_request);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_connect(xenidc_xbgt_channel * channel) {
+ trace();
+
+ channel->phase_two_connect_request.remote_domain_id =
+ channel->remote_domain_id;
+ channel->phase_two_connect_request.recv_ring_ref =
+ channel->ready_ring_reference;
+ channel->phase_two_connect_request.recv_event_channel =
+ channel->ready_event_channel;
+
+ (void)xenidc_work_schedule(&channel->phase_two_connect_1_work);
+}
+
+static void xenidc_xbgt_channel_phase_two_connect_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ xenidc_gnttab_channel_phase_two_connect
+ (&channel->channel, &channel->phase_two_connect_request);
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_connect_2(xenidc_callback * callback) {
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = container_of
+ (xenidc_gnttab_channel_phase_two_connect_request_callback_to
+ (callback),
+ xenidc_xbgt_channel,
+ phase_two_connect_request);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ if (xenidc_callback_query_error(callback) ==
+ XENIDC_ERROR_SUCCESS) {
+ xenidc_xbgt_channel_handle_stimulus(channel,
+ xenidc_xbgt_channel_stimulus_rs);
+ } else {
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rf);
+ }
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect
+ (xenidc_xbgt_channel * channel) {
+ trace();
+
+ (void)xenidc_work_schedule(&channel->phase_two_disconnect_1_work);
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ xenidc_gnttab_channel_phase_two_disconnect
+ (&channel->channel,
+ &channel->phase_two_disconnect_callback);
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect_2
+ (xenidc_callback * callback) {
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = container_of
+ (callback, xenidc_xbgt_channel,
+ phase_two_disconnect_callback);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect
+ (xenidc_xbgt_channel * channel) {
+ trace();
+
+ (void)xenidc_work_schedule(&channel->phase_one_disconnect_1_work);
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect_1(void *data)
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = (xenidc_xbgt_channel *) data;
+
+ xenidc_gnttab_channel_phase_one_disconnect
+ (&channel->channel,
+ &channel->phase_one_disconnect_callback);
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect_2
+ (xenidc_callback * callback) {
+ trace();
+
+ {
+ xenidc_xbgt_channel *channel = container_of
+ (callback, xenidc_xbgt_channel,
+ phase_one_disconnect_callback);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->lock, flags);
+
+ xenidc_xbgt_channel_handle_stimulus
+ (channel, xenidc_xbgt_channel_stimulus_rs);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+ }
+}
+
+static void xenidc_xbgt_channel_complete_disconnect
+ (xenidc_xbgt_channel * channel) {
+ trace();
+
+ xenidc_callback_success(channel->disconnect_callback);
+}
diff -r 47edf571a62d -r 1786d40e66b8 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot
--- /dev/null Sun Nov 20 17:44:51 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot Sun Nov 20 17:45:04 2005
@@ -0,0 +1,109 @@
+digraph enumeration {
+size="7,7"
+
+i[style=filled,fillcolor=green]
+i->i_cn[label="cn\nphase_one_connect"];
+
+i_cn[style=filled,fillcolor=green]
+i_cn->i_cn_dn[label="dn"];
+i_cn->i_cn_rs[label="rs\nregister_watch"];
+
+i_cn_dn[style=filled,fillcolor=orange]
+i_cn_dn->i_cn_dn_rs[label="rs\nclear_store"];
+
+i_cn_rs[style=filled,fillcolor=green]
+i_cn_rs->i_cn_rs_dn[label="dn"];
+i_cn_rs->i_cn_rs[label="pe/od/or/oc"];
+i_cn_rs->i_cn_rs_rs[label="rs\nclear_store"];
+i_cn_rs->i_cn_rs_rf[label="rf\nclear_store"];
+
+i_cn_dn_rs[style=filled,fillcolor=orange]
+i_cn_dn_rs->i_cn_dn_rs_rs[label="rs/rf\nphase_one_disconnect"];
+
+i_cn_rs_dn[style=filled,fillcolor=orange]
+i_cn_rs_dn->i_cn_rs_dn[label="od/or/oc"];
+i_cn_rs_dn->i_cn_rs_dn_rs[label="rs\nunregister_watch"];
+i_cn_rs_dn->i_cn_dn_rs[label="rf\nclear_store"];
+
+i_cn_rs_rs[style=filled,fillcolor=green]
+i_cn_rs_rs->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs->i_cn_rs_rs[label="od/or/oc"];
+i_cn_rs_rs->i_cn_rs_rs_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rf[style=filled,fillcolor=red]
+i_cn_rs_rf->i_cn_dn_rs[label="dn"];
+i_cn_rs_rf->i_cn_rs_rf_rs[label="rs/rf\nphase_one_disconnect"];
+
+i_cn_dn_rs_rs[style=filled,fillcolor=orange]
+i_cn_dn_rs_rs->i[label="rs\ncomplete_disconnect"];
+
+i_cn_rs_dn_rs[style=filled,fillcolor=orange]
+i_cn_rs_dn_rs->i_cn_rs_dn_rs[label="od/or/oc"];
+i_cn_rs_dn_rs->i_cn_dn_rs[label="rs\nclear_store"];
+
+i_cn_rs_rs_dn[style=filled,fillcolor=orange]
+i_cn_rs_rs_dn->i_cn_rs_rs_dn[label="od/or/oc"];
+i_cn_rs_rs_dn->i_cn_rs_dn_rs[label="rs/rf\nunregister_watch"];
+
+i_cn_rs_rs_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs->i_cn_rs_rs_rs[label="ou/oc"];
+i_cn_rs_rs_rs->i_cn_rs_rs_rs_od[label="od/or\nwrite_ready"];
+
+i_cn_rs_rs_rf[style=filled,fillcolor=red]
+i_cn_rs_rs_rf->i_cn_rs_dn_rs[label="dn"];
+i_cn_rs_rs_rf->i_cn_rs_rs_rf[label="od/or/oc"];
+i_cn_rs_rs_rf->i_cn_rs_rf[label="rs\nclear_store"];
+
+i_cn_rs_rf_rs[style=filled,fillcolor=red]
+i_cn_rs_rf_rs->i_cn_dn_rs_rs[label="dn"];
+i_cn_rs_rf_rs->i_cn_rs_rf_rs_rs[label="rs"];
+
+i_cn_rs_rs_rs_od[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od[label="od/or/oc"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rf_rs_rs[style=filled,fillcolor=red]
+i_cn_rs_rf_rs_rs->i[label="dn\ncomplete_disconnect"];
+
+i_cn_rs_rs_rs_od_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs[label="od"];
+i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs_or[label="or/oc\nwrite_connected"];
+
+i_cn_rs_rs_rs_od_rs_or[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or[label="od/or/oc"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rs_rs_od_rs_or_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs[label="od\nclear_store"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs[label="or"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs_oc[label="oc\nphase_two_connect"];
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[label="rs"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs[label="rf\nclear_store"];
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[style=filled,fillcolor=blue]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs[label="rs\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs[label="rf\nclear_store"]
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[style=filled,fillcolor=orange]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="pe/od/or/oc"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_dn[label="rs\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_dn_rs[label="rf\nunregister_watch"]
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs[label="pe/od/or/oc\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs_rs_dn[label="dn\nphase_two_disconnect"]
+}
diff -r 47edf571a62d -r 1786d40e66b8 linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h
--- /dev/null Sun Nov 20 17:44:51 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h Sun Nov 20 17:45:04 2005
@@ -0,0 +1,144 @@
+/*****************************************************************************/
+/* This is a class which uses a xenidc_gnttab_channel (grant-tables based */
+/* message channel class) and xenbus to implement an interdomain message */
+/* channel with grant-tables based message transfer and xenbus based */
+/* bring-up and tear-down handshaking. */
+/* This class is used in the implementation of the xenidc_endpoint class. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef _XENIDC_XBGT_CHANNEL_H
+#define _XENIDC_XBGT_CHANNEL_H
+
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc_gnttab_channel.h>
+
+typedef struct xenidc_xbgt_channel_struct xenidc_xbgt_channel;
+
+typedef enum {
+ xenidc_xbgt_channel_state_i,
+ xenidc_xbgt_channel_state_i_cn,
+ xenidc_xbgt_channel_state_i_cn_dn,
+ xenidc_xbgt_channel_state_i_cn_rs,
+ xenidc_xbgt_channel_state_i_cn_dn_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_dn,
+ xenidc_xbgt_channel_state_i_cn_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rf,
+ xenidc_xbgt_channel_state_i_cn_dn_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rf,
+ xenidc_xbgt_channel_state_i_cn_rs_rf_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od,
+ xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs
+} xenidc_xbgt_channel_state;
+
+typedef enum {
+ xenidc_xbgt_channel_other_state_unknown,
+ xenidc_xbgt_channel_other_state_disconnected,
+ xenidc_xbgt_channel_other_state_ready,
+ xenidc_xbgt_channel_other_state_connected
+} xenidc_xbgt_channel_other_state;
+
+struct xenidc_xbgt_channel_struct {
+ xenidc_gnttab_channel channel;
+
+ struct xenbus_watch watch;
+
+ spinlock_t lock;
+
+ xenidc_xbgt_channel_state state;
+ xenidc_xbgt_channel_other_state other_state;
+
+ const char *local_path;
+ const char *remote_path;
+ domid_t remote_domain_id;
+
+ xenidc_callback *disconnect_callback;
+
+ int ready_ring_reference;
+ int ready_event_channel;
+
+ xenidc_work register_watch_1_work;
+ xenidc_work unregister_watch_1_work;
+ xenidc_work clear_store_1_work;
+ xenidc_work write_ready_1_work;
+ xenidc_work write_connected_1_work;
+ xenidc_work phase_one_connect_1_work;
+ xenidc_work phase_two_connect_1_work;
+ xenidc_work phase_two_disconnect_1_work;
+ xenidc_work phase_one_disconnect_1_work;
+
+ xenidc_gnttab_channel_phase_one_connect_request
+ phase_one_connect_request;
+ xenidc_gnttab_channel_phase_two_connect_request
+ phase_two_connect_request;
+
+ xenidc_callback phase_two_disconnect_callback;
+ xenidc_callback phase_one_disconnect_callback;
+};
+
+/* This class implements the xenidc_channel interface. */
+
+static inline xenidc_channel *xenidc_xbgt_channel_to_channel
+ (xenidc_xbgt_channel * channel) {
+ return xenidc_gnttab_channel_to_channel(&channel->channel);
+}
+
+/* Cast from base class. */
+
+static inline xenidc_xbgt_channel *xenidc_xbgt_channel_gnttab_channel_to
+ (xenidc_gnttab_channel * gnttab_channel) {
+ return container_of(gnttab_channel, xenidc_xbgt_channel, channel);
+}
+
+/* Cast from base class. */
+
+static inline xenidc_xbgt_channel *xenidc_xbgt_channel_channel_to
+ (xenidc_channel * channel) {
+ return xenidc_xbgt_channel_gnttab_channel_to
+ (xenidc_gnttab_channel_channel_to(channel));
+}
+
+extern int xenidc_xbgt_channel_init(xenidc_xbgt_channel * channel);
+
+/* xenidc_xbgt_channel_connect called to connect the channel. Passed the */
+/* xenbus specific addressing information of the remote domain and device. */
+
+extern void xenidc_xbgt_channel_connect
+ (xenidc_xbgt_channel * channel,
+ const char *local_path, const char *remote_path, domid_t remote_domain_id);
+
+/* Called to disconnect. Callback completes after base channel class has */
+/* disconnected its client. */
+
+extern void xenidc_xbgt_channel_disconnect
+ (xenidc_xbgt_channel * channel, xenidc_callback * callback);
+
+extern void xenidc_xbgt_channel_exit(xenidc_xbgt_channel * channel);
+
+#endif
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
reply other threads:[~2005-11-21 13:19 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1132579142.31295.119.camel@localhost.localdomain \
--to=harry@hebutterworth.freeserve.co.uk \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.