* [PATCH][8/17] USB virt 2.6 split driver---xbgt channel
@ 2005-11-21 13:19 harry
0 siblings, 0 replies; only message in thread
From: harry @ 2005-11-21 13:19 UTC (permalink / raw)
To: xen-devel
[-- 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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2005-11-21 13:19 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-11-21 13:19 [PATCH][8/17] USB virt 2.6 split driver---xbgt channel harry
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.