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 +#include +#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 +#include + +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