diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Sun Nov 20 17:45:16 2005 @@ -12,3 +12,6 @@ xenidc-objs += xenidc_vaddress.o xenidc-objs += xenidc_gnttab_channel.o xenidc-objs += xenidc_xbgt_channel.o +xenidc-objs += xenidc_gateway.o +xenidc-objs += xenidc_gateway_initiator_resource.o +xenidc-objs += xenidc_gateway_target_resource.o diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c --- /dev/null Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c Sun Nov 20 17:45:16 2005 @@ -0,0 +1,1216 @@ +/*****************************************************************************/ +/* A communication 'gateway' object which allows the client to send messages */ +/* and transactions bi-directionally over a xenidc_channel. */ +/* */ +/* 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 */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include "xenidc_gateway_initiator_resource.h" +#include "xenidc_gateway_target_resource.h" +#include "xenidc_trace.h" + +typedef enum { + xenidc_gateway_stimulus_mt, /* Message or transaction queued. */ + xenidc_gateway_stimulus_cc, /* Channel connect. */ + xenidc_gateway_stimulus_cm, /* Channel message. */ + xenidc_gateway_stimulus_cd, /* Channel disconnect. */ + xenidc_gateway_stimulus_km, /* Kick messages and transactions completed. */ + xenidc_gateway_stimulus_kc, /* Kick channel messages completed. */ + xenidc_gateway_stimulus_ic, /* Initiator resource completed. */ + xenidc_gateway_stimulus_ii, /* Initiator resources idle. */ + xenidc_gateway_stimulus_tc, /* Target resource completed. */ + xenidc_gateway_stimulus_ti, /* Target resources idle. */ + xenidc_gateway_stimulus_lc, /* Client connect completed. */ + xenidc_gateway_stimulus_lg, /* Client disconnect called. */ + xenidc_gateway_stimulus_ld, /* Client disconnect completed. */ +} xenidc_gateway_stimulus; + +static void xenidc_gateway_handle_stimulus + (xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus); + +static void xenidc_gateway_channel_connect(void *context); + +static void xenidc_gateway_handle_channel_message + (void *context, xenidc_channel_message * message); + +static void xenidc_gateway_channel_disconnect + (void *context, xenidc_callback * callback); + +static int xenidc_gateway_init_or_exit(xenidc_gateway * gateway, int exit); + +int xenidc_gateway_init + (xenidc_gateway * gateway, + xenidc_channel * channel, + void (*connect) (xenidc_gateway * gateway), void (*handle_message) + (xenidc_gateway * gateway, xenidc_gateway_message * message), + void (*handle_transaction) + (xenidc_gateway * gateway, xenidc_gateway_transaction * transaction), + void (*disconnect) + (xenidc_gateway * gateway, xenidc_callback * callback), + u32 initiator_quota, + xenidc_buffer_byte_count initiator_maximum_byte_count, + u32 target_quota, xenidc_buffer_byte_count target_maximum_byte_count) { + trace(); + + gateway->channel = channel; + gateway->connect = connect; + gateway->handle_message = handle_message; + gateway->handle_transaction = handle_transaction; + gateway->disconnect = disconnect; + + gateway->initiator_quota = initiator_quota; + gateway->target_quota = target_quota; + gateway->target_maximum_byte_count = target_maximum_byte_count; + + xenidc_channel_install_client + (channel, + gateway, + xenidc_gateway_channel_connect, + xenidc_gateway_handle_channel_message, + xenidc_gateway_channel_disconnect); + + return xenidc_gateway_init_or_exit(gateway, 0); +} + +static void xenidc_gateway_kick_messages_and_transactions_1(void *data); + +static void xenidc_gateway_kick_messages_and_transactions_2 + (xenidc_callback * callback); + +static void xenidc_gateway_kick_channel_messages_1(void *data); + +static void xenidc_gateway_kick_channel_messages_2(xenidc_callback * callback); + +static void xenidc_gateway_connect_client_1(void *data); + +static void xenidc_gateway_disconnect_client_1(void *data); + +static void xenidc_gateway_disconnect_client_2(xenidc_callback * callback); + +static int xenidc_gateway_init_or_exit(xenidc_gateway * gateway, int exit) +{ + trace(); + + { + int return_value = 0; + + if (exit) { + goto EXIT; + } + + INIT_LIST_HEAD(&gateway->initiator_resource_list); + + if (gateway->initiator_quota != 0) { + gateway->initiator_resources = vmalloc + (sizeof(xenidc_gateway_initiator_resource) + * gateway->initiator_quota); + + if (gateway->initiator_resources == NULL) { + trace0 + ("failed to allocate initiator resources"); + + return_value = -ENOMEM; + + goto EXIT_NO_INITIATOR_RESOURCES; + } + + { + u32 i; + + for (i = 0; i < gateway->initiator_quota; i++) { + xenidc_gateway_initiator_resource + *resource = + &gateway->initiator_resources[i]; + + xenidc_gateway_initiator_resource_init + (resource, + gateway, + xenidc_gateway_kick_messages_and_transactions_2, + i); + + list_add_tail + (xenidc_gateway_initiator_resource_to_link + (resource), + &gateway->initiator_resource_list); + } + } + } + + INIT_LIST_HEAD(&gateway->target_resource_list); + + if (gateway->target_quota != 0) { + gateway->target_resources = vmalloc + ((sizeof(xenidc_gateway_target_resource) + * gateway->target_quota) + + + (gateway->target_maximum_byte_count + * gateway->target_quota) + ); + + if (gateway->target_resources == NULL) { + trace0("failed to allocate target resources"); + + return_value = -ENOMEM; + + goto EXIT_NO_TARGET_RESOURCES; + } + + { + xenidc_local_buffer_reference buffer_area = + xenidc_vaddress_create_lbr + (&gateway->target_resources + [gateway->target_quota], + gateway->target_maximum_byte_count * + gateway->target_quota); + + u32 i; + + for (i = 0; i < gateway->target_quota; i++) { + xenidc_gateway_target_resource *resource + = &gateway->target_resources[i]; + + xenidc_local_buffer_reference buffer = + buffer_area; + + xenidc_local_buffer_reference_truncate + (&buffer, + gateway-> + target_maximum_byte_count); + + xenidc_gateway_target_resource_init + (resource, + gateway, + xenidc_gateway_kick_channel_messages_2, + buffer); + + list_add_tail + (xenidc_gateway_target_resource_to_link + (resource), + &gateway->target_resource_list); + + xenidc_local_buffer_reference_advance + (&buffer_area, + gateway-> + target_maximum_byte_count); + } + } + } + + spin_lock_init(&gateway->lock); + + gateway->state = xenidc_gateway_state_i; + + INIT_LIST_HEAD(&gateway->message_and_transaction_list); + INIT_LIST_HEAD(&gateway->channel_message_list); + + xenidc_work_init + (&gateway->kick_messages_and_transactions_1_work, + xenidc_gateway_kick_messages_and_transactions_1, gateway); + + xenidc_work_init + (&gateway->kick_channel_messages_1_work, + xenidc_gateway_kick_channel_messages_1, gateway); + + xenidc_work_init + (&gateway->connect_client_1_work, + xenidc_gateway_connect_client_1, gateway); + + xenidc_work_init + (&gateway->disconnect_client_1_work, + xenidc_gateway_disconnect_client_1, gateway); + + xenidc_callback_init + (&gateway->disconnect_client_2_callback, + xenidc_gateway_disconnect_client_2); + + gateway->kick_messages_and_transactions_out = 0; + gateway->kick_channel_messages_out = 0; + gateway->initiator_resources_out = 0; + gateway->target_resources_out = 0; + + return 0; + + EXIT: + + if (gateway->target_quota != 0) { + vfree(gateway->target_resources); + } + + EXIT_NO_TARGET_RESOURCES: + + if (gateway->initiator_quota != 0) { + vfree(gateway->initiator_resources); + } + + EXIT_NO_INITIATOR_RESOURCES: + + return return_value; + } +} + +void xenidc_gateway_submit_message + (xenidc_gateway * gateway, xenidc_gateway_message * message) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + list_add_tail + (xenidc_gateway_message_to_link(message), + &gateway->message_and_transaction_list); + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_mt); + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +void xenidc_gateway_submit_transaction + (xenidc_gateway * gateway, xenidc_gateway_transaction * transaction) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + list_add_tail + (xenidc_gateway_transaction_to_link(transaction), + &gateway->message_and_transaction_list); + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_mt); + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +void xenidc_gateway_exit(xenidc_gateway * gateway) +{ + trace(); + + (void)xenidc_gateway_init_or_exit(gateway, 1); +} + +static void xenidc_gateway_channel_connect(void *context) +{ + trace(); + + { + xenidc_gateway *gateway = (xenidc_gateway *) context; + + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_cc); + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +static void xenidc_gateway_handle_channel_message + (void *context, xenidc_channel_message * message) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + xenidc_gateway *gateway = (xenidc_gateway *) context; + + xenidc_gateway_ring_element_header header; + + if (xenidc_local_buffer_reference_copy_out + (&message->message_lbr, &header, sizeof(header)) + != sizeof(header) + ) { + goto PROTOCOL_ERROR; + } + + if (header.type == XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS) { + xenidc_local_buffer_reference status_lbr = + message->message_lbr; + + xenidc_gateway_status_ring_element status_element; + + if (xenidc_local_buffer_reference_copy_out + (&status_lbr, &status_element, + sizeof(status_element)) + != sizeof(status_element) + ) { + goto PROTOCOL_ERROR; + } + + xenidc_local_buffer_reference_advance + (&status_lbr, sizeof(status_element)); + + if (status_element.id >= gateway->initiator_quota) { + goto PROTOCOL_ERROR; + } + + { + xenidc_gateway_initiator_resource *resource = + &gateway-> + initiator_resources[status_element.id]; + + if (xenidc_gateway_initiator_resource_handle_status(resource, status_element.error, status_lbr) + != 0) { + goto PROTOCOL_ERROR; + } + } + + xenidc_callback_success + (xenidc_channel_message_to_callback(message)); + } else { + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + list_add_tail + (xenidc_channel_message_to_link(message), + &gateway->channel_message_list); + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_cm); + + spin_unlock_irqrestore(&gateway->lock, flags); + } + } + + return; + + PROTOCOL_ERROR: + + xenidc_callback_complete + (xenidc_channel_message_to_callback(message), + XENIDC_ERROR_INVALID_PROTOCOL); +} + +static void xenidc_gateway_channel_disconnect + (void *context, xenidc_callback * callback) { + trace(); + + { + xenidc_gateway *gateway = (xenidc_gateway *) context; + + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + gateway->channel_disconnect_callback = callback; + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_cd); + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +void xenidc_gateway_submit_channel_message + (xenidc_gateway * gateway, xenidc_channel_message * message) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + xenidc_channel_submit_message(gateway->channel, message); +} + +void xenidc_gateway_submit_message_to_client + (xenidc_gateway * gateway, xenidc_gateway_message * message) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + gateway->handle_message(gateway, message); +} + +void xenidc_gateway_submit_transaction_to_client + (xenidc_gateway * gateway, xenidc_gateway_transaction * transaction) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + gateway->handle_transaction(gateway, transaction); +} + +static void xenidc_gateway_invalid_stimulus + (xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus); + +static void xenidc_gateway_kick_messages_and_transactions + (xenidc_gateway * gateway); + +static void xenidc_gateway_fail_out_messages_and_transactions + (xenidc_gateway * gateway); + +static void xenidc_gateway_kick_channel_messages(xenidc_gateway * gateway); + +static void xenidc_gateway_complete_channel_messages(xenidc_gateway * gateway); + +static void xenidc_gateway_connect_client(xenidc_gateway * gateway); + +static void xenidc_gateway_disconnect_client(xenidc_gateway * gateway); + +static void xenidc_gateway_abort_initiator_resources(xenidc_gateway * gateway); + +static void xenidc_gateway_test_initiator_resources(xenidc_gateway * gateway); + +static void xenidc_gateway_test_target_resources(xenidc_gateway * gateway); + +static void xenidc_gateway_complete_channel_disconnect + (xenidc_gateway * gateway); + +static void xenidc_gateway_handle_stimulus + (xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus) { + trace3 + ("gateway %p in state %d received stimulus %d", + gateway, gateway->state, stimulus); + + switch (gateway->state) { + case xenidc_gateway_state_i: + /* Channel disconnected. */ + /* Client disconnected. */ + /* No messages or transactions queued. */ + /* No channel messages queued. */ + /* Initiator resources idle. */ + /* Target resources idle. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_cc: + gateway->state = xenidc_gateway_state_i_cc; + xenidc_gateway_connect_client(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc: + /* Channel connected. */ + /* Client connecting. */ + /* Maybe messages or transactions queued. */ + /* Maybe channel messages queued. */ + /* Initiator resources idle. */ + /* Target resources idle. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_mt: + case xenidc_gateway_stimulus_cm: + break; + case xenidc_gateway_stimulus_cd: + gateway->state = xenidc_gateway_state_i_cc_cd; + xenidc_gateway_complete_channel_messages(gateway); + break; + case xenidc_gateway_stimulus_lc: + gateway->state = xenidc_gateway_state_i_cc_lc; + xenidc_gateway_kick_messages_and_transactions(gateway); + xenidc_gateway_kick_channel_messages(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_cd: + /* Channel disconnecting. */ + /* Client connecting. */ + /* Maybe messages or transactions queued. */ + /* No channel messages queued. */ + /* Initiator resources idle. */ + /* Target resources idle. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_mt: + break; + case xenidc_gateway_stimulus_lc: + gateway->state = xenidc_gateway_state_i_cc_cd_lc; + xenidc_gateway_disconnect_client(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_lc: + /* Channel connected. */ + /* Client connected. */ + /* Maybe messages or transactions queued. */ + /* Maybe channel messages queued. */ + /* Maybe initiator resources busy. */ + /* Maybe target resources busy. */ + /* Maybe kicking m/t. */ + /* Maybe kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_mt: + xenidc_gateway_kick_messages_and_transactions(gateway); + break; + case xenidc_gateway_stimulus_cm: + xenidc_gateway_kick_channel_messages(gateway); + break; + case xenidc_gateway_stimulus_cd: + gateway->state = xenidc_gateway_state_i_cc_lc_cd; + xenidc_gateway_complete_channel_messages(gateway); + xenidc_gateway_kick_messages_and_transactions(gateway); + xenidc_gateway_kick_channel_messages(gateway); + break; + case xenidc_gateway_stimulus_km: + case xenidc_gateway_stimulus_kc: + break; + case xenidc_gateway_stimulus_ic: + case xenidc_gateway_stimulus_ii: + xenidc_gateway_kick_messages_and_transactions(gateway); + break; + case xenidc_gateway_stimulus_tc: + case xenidc_gateway_stimulus_ti: + xenidc_gateway_kick_channel_messages(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_lc_cd: + /* Channel disconnecting. */ + /* Client connected. */ + /* Maybe messages or transactions queued. */ + /* No channel messages queued. */ + /* Maybe initiator resources busy. */ + /* Maybe target resources busy. */ + /* Kicking m/t. */ + /* Kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_mt: + break; + case xenidc_gateway_stimulus_km: + case xenidc_gateway_stimulus_kc: + gateway->state = xenidc_gateway_state_i_cc_lc_cd_km; + break; + case xenidc_gateway_stimulus_ic: + case xenidc_gateway_stimulus_ii: + case xenidc_gateway_stimulus_tc: + case xenidc_gateway_stimulus_ti: + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_lc_cd_km: + /* Channel disconnecting. */ + /* Client connected. */ + /* Maybe messages or transactions queued. */ + /* No channel messages queued. */ + /* Maybe initiator resources busy. */ + /* Maybe target resources busy. */ + /* One of kicking m/t or cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_mt: + break; + case xenidc_gateway_stimulus_km: + case xenidc_gateway_stimulus_kc: + gateway->state = xenidc_gateway_state_i_cc_cd_lc; + xenidc_gateway_disconnect_client(gateway); + break; + case xenidc_gateway_stimulus_ic: + case xenidc_gateway_stimulus_ii: + case xenidc_gateway_stimulus_tc: + case xenidc_gateway_stimulus_ti: + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_cd_lc: + /* Channel disconnecting. */ + /* Calling client disconnect. */ + /* Maybe messages or transactions queued. */ + /* No channel messages queued. */ + /* Maybe initiator resources busy. */ + /* Maybe target resources busy. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_mt: + break; + case xenidc_gateway_stimulus_ic: + case xenidc_gateway_stimulus_ii: + case xenidc_gateway_stimulus_tc: + case xenidc_gateway_stimulus_ti: + break; + case xenidc_gateway_stimulus_lg: + gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg; + xenidc_gateway_fail_out_messages_and_transactions + (gateway); + xenidc_gateway_abort_initiator_resources(gateway); + break; + case xenidc_gateway_stimulus_ld: + gateway->state = xenidc_gateway_state_i_cc_cd_lc_ld; + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_cd_lc_lg: + /* Channel disconnecting. */ + /* Client disconnecting. */ + /* No messages or transactions queued. */ + /* No channel messages queued. */ + /* Maybe initiator resources busy. */ + /* Maybe target resources busy. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_mt: + break; + case xenidc_gateway_stimulus_ic: + case xenidc_gateway_stimulus_ii: + case xenidc_gateway_stimulus_tc: + case xenidc_gateway_stimulus_ti: + break; + case xenidc_gateway_stimulus_ld: + gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld; + xenidc_gateway_test_target_resources(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_cd_lc_ld: + /* Channel disconnecting. */ + /* Client disconnected but call still in progress. */ + /* No messages or transactions queued. */ + /* No channel messages queued. */ + /* Maybe initiator resources busy. */ + /* Maybe target resources busy. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_ic: + case xenidc_gateway_stimulus_ii: + case xenidc_gateway_stimulus_tc: + case xenidc_gateway_stimulus_ti: + break; + case xenidc_gateway_stimulus_lg: + gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld; + xenidc_gateway_test_target_resources(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_cd_lc_lg_ld: + /* Channel disconnecting. */ + /* Client disconnected. */ + /* No messages or transactions queued. */ + /* No channel messages queued. */ + /* Maybe initiator resources busy. */ + /* Test target resources or target resources busy. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_ic: + case xenidc_gateway_stimulus_ii: + case xenidc_gateway_stimulus_tc: + break; + case xenidc_gateway_stimulus_ti: + gateway->state = + xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti; + xenidc_gateway_test_initiator_resources(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + case xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti: + /* Channel disconnecting. */ + /* Client disconnected. */ + /* No messages or transactions queued. */ + /* No channel messages queued. */ + /* Test initiator resources or initiator resources busy. */ + /* Target resources idle. */ + /* Not kicking m/t. */ + /* Not kicking cm. */ + switch (stimulus) { + case xenidc_gateway_stimulus_ic: + break; + case xenidc_gateway_stimulus_ii: + gateway->state = xenidc_gateway_state_i; + xenidc_gateway_complete_channel_disconnect(gateway); + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } + break; + default: + xenidc_gateway_invalid_stimulus(gateway, stimulus); + break; + } +} + +static void xenidc_gateway_invalid_stimulus + (xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus) { + trace(); + + printk + (KERN_ERR "xenidc: gateway %p in state %d" + "received invalid stimulus %d", gateway, gateway->state, stimulus); +} + +static void xenidc_gateway_kick_messages_and_transactions + (xenidc_gateway * gateway) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + if (!gateway->kick_messages_and_transactions_out) { + gateway->kick_messages_and_transactions_out = 1; + + (void)xenidc_work_schedule + (&gateway->kick_messages_and_transactions_1_work); + } +} + +static void xenidc_gateway_kick_messages_and_transactions_1(void *data) +{ + trace(); + + { + xenidc_gateway *gateway = (xenidc_gateway *) data; + + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + while ((!list_empty(&gateway->message_and_transaction_list)) + && (!list_empty(&gateway->initiator_resource_list)) + ) { + xenidc_gateway_message_and_transaction_header *header = + list_entry(gateway->message_and_transaction_list. + next, + xenidc_gateway_message_and_transaction_header, + XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK); + + xenidc_gateway_initiator_resource *resource = list_entry + (gateway->initiator_resource_list.next, + xenidc_gateway_initiator_resource, + XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK); + + list_del_init + (xenidc_gateway_message_and_transaction_header_to_link + (header) + ); + + list_del_init + (xenidc_gateway_initiator_resource_to_link + (resource)); + + gateway->initiator_resources_out++; + + spin_unlock_irqrestore(&gateway->lock, flags); + + xenidc_gateway_initiator_resource_start(resource, + header); + + spin_lock_irqsave(&gateway->lock, flags); + } + + gateway->kick_messages_and_transactions_out = 0; + + xenidc_gateway_handle_stimulus(gateway, + xenidc_gateway_stimulus_km); + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +static void xenidc_gateway_kick_messages_and_transactions_2 + (xenidc_callback * callback) { + trace(); + + { + xenidc_gateway_initiator_resource *resource = + xenidc_gateway_initiator_resource_callback_to(callback); + + xenidc_gateway *gateway = + xenidc_gateway_initiator_resource_query_gateway(resource); + + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + list_add_tail + (xenidc_gateway_initiator_resource_to_link(resource), + &gateway->initiator_resource_list); + + if (--gateway->initiator_resources_out != 0) { + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_ic); + } else { + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_ii); + } + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +static void xenidc_gateway_fail_out_messages_and_transactions + (xenidc_gateway * gateway) { + trace(); + + while (!list_empty(&gateway->message_and_transaction_list)) { + xenidc_gateway_message_and_transaction_header *header = + list_entry(gateway->message_and_transaction_list.next, + xenidc_gateway_message_and_transaction_header, + XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK); + + list_del_init + (xenidc_gateway_message_and_transaction_header_to_link + (header)); + + xenidc_callback_complete + (xenidc_gateway_message_and_transaction_header_to_callback + (header), XENIDC_ERROR_DISCONNECT); + } +} + +static void xenidc_gateway_kick_channel_messages(xenidc_gateway * gateway) +{ + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + if (!gateway->kick_channel_messages_out) { + gateway->kick_channel_messages_out = 1; + + (void)xenidc_work_schedule(&gateway-> + kick_channel_messages_1_work); + } +} + +static void xenidc_gateway_kick_channel_messages_1(void *data) +{ + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + xenidc_gateway *gateway = (xenidc_gateway *) data; + + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + while ((!list_empty(&gateway->channel_message_list)) + && (!list_empty(&gateway->target_resource_list)) + ) { + xenidc_channel_message *message = list_entry + (gateway->channel_message_list.next, + xenidc_channel_message, + XENIDC_CHANNEL_MESSAGE_LINK); + + xenidc_gateway_target_resource *resource = list_entry + (gateway->target_resource_list.next, + xenidc_gateway_target_resource, + XENIDC_GATEWAY_TARGET_RESOURCE_LINK); + + list_del_init(xenidc_channel_message_to_link(message)); + + { + xenidc_gateway_ring_element_header header; + + if (xenidc_local_buffer_reference_copy_out + (&message->message_lbr, &header, + sizeof(header)) + != sizeof(header) + ) { + goto PROTOCOL_ERROR; + } + + if (header.type == + XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE) { + xenidc_local_buffer_reference + message_lbr = message->message_lbr; + + xenidc_local_buffer_reference_advance + (&message_lbr, + sizeof + (xenidc_gateway_message_ring_element) + ); + + list_del_init + (xenidc_gateway_target_resource_to_link + (resource)); + + gateway->target_resources_out++; + + spin_unlock_irqrestore(&gateway->lock, + flags); + + xenidc_gateway_target_resource_start_message + (resource, message_lbr); + + spin_lock_irqsave(&gateway->lock, + flags); + + xenidc_callback_success + (xenidc_channel_message_to_callback + (message)); + } else if (header.type == + XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS) + { + xenidc_local_buffer_reference + parameters_lbr = + message->message_lbr; + + xenidc_gateway_parameters_ring_element + parameters_element; + + if (xenidc_local_buffer_reference_copy_out(¶meters_lbr, ¶meters_element, sizeof(parameters_element) + ) + != sizeof(parameters_element) + ) { + goto PROTOCOL_ERROR; + } + + xenidc_local_buffer_reference_advance + (¶meters_lbr, + sizeof(parameters_element)); + + list_del_init + (xenidc_gateway_target_resource_to_link + (resource)); + + gateway->target_resources_out++; + + spin_unlock_irqrestore(&gateway->lock, + flags); + + xenidc_gateway_target_resource_start_transaction + (resource, + parameters_element.id, + parameters_lbr, + parameters_element. + status_byte_count); + + spin_lock_irqsave(&gateway->lock, + flags); + + xenidc_callback_success + (xenidc_channel_message_to_callback + (message)); + } else { + PROTOCOL_ERROR: + + xenidc_callback_complete + (xenidc_channel_message_to_callback + (message), + XENIDC_ERROR_INVALID_PROTOCOL); + } + } + } + + gateway->kick_channel_messages_out = 0; + + xenidc_gateway_handle_stimulus(gateway, + xenidc_gateway_stimulus_kc); + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +static void xenidc_gateway_kick_channel_messages_2(xenidc_callback * callback) { + trace(); + + { + xenidc_gateway_target_resource *resource = + xenidc_gateway_target_resource_callback_to(callback); + + xenidc_gateway *gateway = + xenidc_gateway_target_resource_query_gateway(resource); + + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + list_add_tail + (xenidc_gateway_target_resource_to_link(resource), + &gateway->target_resource_list); + + if (--gateway->target_resources_out != 0) { + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_tc); + } else { + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_ti); + } + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +static void xenidc_gateway_complete_channel_messages(xenidc_gateway * gateway) { + trace(); + + while (!list_empty(&gateway->channel_message_list)) { + xenidc_channel_message *message = list_entry + (gateway->channel_message_list.next, + xenidc_channel_message, + XENIDC_CHANNEL_MESSAGE_LINK); + + list_del_init(xenidc_channel_message_to_link(message)); + + xenidc_callback_success + (xenidc_channel_message_to_callback(message)); + } +} + +static void xenidc_gateway_connect_client(xenidc_gateway * gateway) +{ + trace(); + + (void)xenidc_work_schedule(&gateway->connect_client_1_work); +} + +static void xenidc_gateway_connect_client_1(void *data) +{ + trace(); + + { + xenidc_gateway *gateway = (xenidc_gateway *) data; + + gateway->connect(gateway); + + { + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_lc); + + spin_unlock_irqrestore(&gateway->lock, flags); + } + } +} + +static void xenidc_gateway_disconnect_client(xenidc_gateway * gateway) +{ + trace(); + + (void)xenidc_work_schedule(&gateway->disconnect_client_1_work); +} + +static void xenidc_gateway_disconnect_client_1(void *data) +{ + trace(); + + { + xenidc_gateway *gateway = (xenidc_gateway *) data; + + gateway->disconnect(gateway, + &gateway->disconnect_client_2_callback); + + { + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_lg); + + spin_unlock_irqrestore(&gateway->lock, flags); + } + } +} + +static void xenidc_gateway_disconnect_client_2(xenidc_callback * callback) +{ + trace(); + + { + xenidc_gateway *gateway = container_of + (callback, xenidc_gateway, disconnect_client_2_callback); + + unsigned long flags; + + spin_lock_irqsave(&gateway->lock, flags); + + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_ld); + + spin_unlock_irqrestore(&gateway->lock, flags); + } +} + +static void xenidc_gateway_abort_initiator_resources(xenidc_gateway * gateway) { + trace(); + + { + u32 i; + + for (i = 0; i < gateway->initiator_quota; i++) { + xenidc_gateway_initiator_resource_abort + (&gateway->initiator_resources[i], + XENIDC_ERROR_DISCONNECT); + } + } +} + +static void xenidc_gateway_test_initiator_resources(xenidc_gateway * gateway) { + trace(); + + if (gateway->initiator_resources_out == 0) { + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_ii); + } +} + +static void xenidc_gateway_test_target_resources(xenidc_gateway * gateway) { + trace(); + + if (gateway->target_resources_out == 0) { + xenidc_gateway_handle_stimulus + (gateway, xenidc_gateway_stimulus_ti); + } +} + +static void xenidc_gateway_complete_channel_disconnect(xenidc_gateway * gateway) { + trace(); + + xenidc_callback_success(gateway->channel_disconnect_callback); +} diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c --- /dev/null Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c Sun Nov 20 17:45:16 2005 @@ -0,0 +1,382 @@ +/*****************************************************************************/ +/* The xenidc_gateway_initiator_resource object performs the initiator-side */ +/* part of the processing of a client message or transaction sent across the */ +/* gateway. */ +/* */ +/* 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 */ +/* */ +/*****************************************************************************/ + +#include +#include "xenidc_gateway_initiator_resource.h" +#include "xenidc_trace.h" + +extern void xenidc_gateway_submit_channel_message + (xenidc_gateway * gateway, xenidc_channel_message * message); + +static void xenidc_gateway_initiator_resource_handle_stimulus + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway_initiator_resource_stimulus stimulus); + +static void xenidc_gateway_initiator_resource_channel_message_callback + (xenidc_callback * callback); + +void xenidc_gateway_initiator_resource_init + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway * gateway, xenidc_callback_function callback, int id) { + trace(); + + xenidc_callback_init(&resource->callback, callback); + + resource->gateway = gateway; + + resource->id = id; + + spin_lock_init(&resource->lock); + + resource->state = xenidc_gateway_initiator_resource_state_i; + + xenidc_callback_init + (xenidc_channel_message_to_callback(&resource->channel_message), + xenidc_gateway_initiator_resource_channel_message_callback); +} + +void xenidc_gateway_initiator_resource_start + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway_message_and_transaction_header * header) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + resource->header = header; + + resource->error = XENIDC_ERROR_SUCCESS; + + { + xenidc_gateway_initiator_resource_stimulus stimulus; + + if (header->transaction_not_message) { + xenidc_gateway_transaction *transaction = + xenidc_gateway_transaction_header_to(header); + + resource->element_lbr = xenidc_vaddress_create_lbr + (&resource->parameters_element, + sizeof(resource->parameters_element) + ); + + resource->channel_message.message_lbr = + xenidc_concatenate_create_lbr + (&resource->base, + &resource->element_lbr, + &transaction->parameters_lbr); + + memset + (&resource->parameters_element, + 0, sizeof(resource->parameters_element) + ); + + resource->parameters_element.header.type = + XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS; + + resource->parameters_element.id = resource->id; + + resource->parameters_element.status_byte_count = + xenidc_local_buffer_reference_query_byte_count + (&transaction->status_lbr); + + stimulus = + xenidc_gateway_initiator_resource_stimulus_st; + } else { + xenidc_gateway_message *message = + xenidc_gateway_message_header_to(header); + + resource->element_lbr = xenidc_vaddress_create_lbr + (&resource->message_element, + sizeof(resource->message_element) + ); + + resource->channel_message.message_lbr = + xenidc_concatenate_create_lbr + (&resource->base, + &resource->element_lbr, &message->message_lbr); + + memset + (&resource->message_element, + 0, sizeof(resource->message_element) + ); + + resource->parameters_element.header.type = + XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE; + + stimulus = + xenidc_gateway_initiator_resource_stimulus_sm; + } + + { + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + xenidc_gateway_initiator_resource_handle_stimulus + (resource, stimulus); + + spin_unlock_irqrestore(&resource->lock, flags); + } + + xenidc_gateway_submit_channel_message + (resource->gateway, &resource->channel_message); + } +} + +void xenidc_gateway_initiator_resource_abort + (xenidc_gateway_initiator_resource * resource, xenidc_error error) { + trace(); + + { + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + resource->aborted_error = error; + + xenidc_gateway_initiator_resource_handle_stimulus + (resource, xenidc_gateway_initiator_resource_stimulus_ab); + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +static void xenidc_gateway_initiator_resource_channel_message_callback + (xenidc_callback * callback) { + trace(); + + { + xenidc_gateway_initiator_resource *resource = container_of + (callback, + xenidc_gateway_initiator_resource, + channel_message.callback); + + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + xenidc_gateway_initiator_resource_handle_stimulus + (resource, xenidc_gateway_initiator_resource_stimulus_sc); + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +int xenidc_gateway_initiator_resource_handle_status + (xenidc_gateway_initiator_resource * resource, + xenidc_error error, xenidc_local_buffer_reference status_lbr) { + trace(); + + { + int return_value = -1; + + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + if ((resource->state + == xenidc_gateway_initiator_resource_state_i_st) + || + (resource->state + == xenidc_gateway_initiator_resource_state_i_st_sc) + ) { + xenidc_gateway_transaction *transaction = + xenidc_gateway_transaction_header_to(resource-> + header); + + if (xenidc_local_buffer_reference_query_byte_count + (&status_lbr) + == + xenidc_local_buffer_reference_query_byte_count + (&transaction->status_lbr) + ) { + xenidc_local_buffer_reference_copy + (&transaction->status_lbr, &status_lbr); + + resource->error = error; + + xenidc_gateway_initiator_resource_handle_stimulus + (resource, + xenidc_gateway_initiator_resource_stimulus_ts); + + return_value = 0; + } + } + + spin_unlock_irqrestore(&resource->lock, flags); + + return return_value; + } +} + +static void xenidc_gateway_initiator_resource_invalid_stimulus + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway_initiator_resource_stimulus stimulus); + +static void xenidc_gateway_initiator_resource_set_aborted + (xenidc_gateway_initiator_resource * resource); + +static void xenidc_gateway_initiator_resource_complete + (xenidc_gateway_initiator_resource * resource); + +static void xenidc_gateway_initiator_resource_handle_stimulus + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway_initiator_resource_stimulus stimulus) { + trace3 + ("gateway initiator resource %p in state %d received stimulus %d", + resource, resource->state, stimulus); + + switch (resource->state) { + case xenidc_gateway_initiator_resource_state_i: + switch (stimulus) { + case xenidc_gateway_initiator_resource_stimulus_sm: + resource->state = + xenidc_gateway_initiator_resource_state_i_sm; + break; + case xenidc_gateway_initiator_resource_stimulus_st: + resource->state = + xenidc_gateway_initiator_resource_state_i_st; + break; + case xenidc_gateway_initiator_resource_stimulus_ab: + break; + default: + xenidc_gateway_initiator_resource_invalid_stimulus + (resource, stimulus); + break; + } + break; + case xenidc_gateway_initiator_resource_state_i_sm: + switch (stimulus) { + case xenidc_gateway_initiator_resource_stimulus_ab: + break; + case xenidc_gateway_initiator_resource_stimulus_sc: + resource->state = + xenidc_gateway_initiator_resource_state_i; + xenidc_gateway_initiator_resource_complete(resource); + break; + default: + xenidc_gateway_initiator_resource_invalid_stimulus + (resource, stimulus); + break; + } + break; + case xenidc_gateway_initiator_resource_state_i_st: + switch (stimulus) { + case xenidc_gateway_initiator_resource_stimulus_ab: + resource->state = + xenidc_gateway_initiator_resource_state_i_st_ab; + break; + case xenidc_gateway_initiator_resource_stimulus_sc: + resource->state = + xenidc_gateway_initiator_resource_state_i_st_sc; + break; + case xenidc_gateway_initiator_resource_stimulus_ts: + resource->state = + xenidc_gateway_initiator_resource_state_i_st_ts; + break; + default: + xenidc_gateway_initiator_resource_invalid_stimulus + (resource, stimulus); + break; + } + break; + case xenidc_gateway_initiator_resource_state_i_st_ab: + switch (stimulus) { + case xenidc_gateway_initiator_resource_stimulus_sc: + resource->state = + xenidc_gateway_initiator_resource_state_i; + xenidc_gateway_initiator_resource_set_aborted(resource); + xenidc_gateway_initiator_resource_complete(resource); + break; + default: + xenidc_gateway_initiator_resource_invalid_stimulus + (resource, stimulus); + break; + } + break; + case xenidc_gateway_initiator_resource_state_i_st_sc: + switch (stimulus) { + case xenidc_gateway_initiator_resource_stimulus_ab: + resource->state = + xenidc_gateway_initiator_resource_state_i; + xenidc_gateway_initiator_resource_set_aborted(resource); + xenidc_gateway_initiator_resource_complete(resource); + break; + case xenidc_gateway_initiator_resource_stimulus_ts: + resource->state = + xenidc_gateway_initiator_resource_state_i; + xenidc_gateway_initiator_resource_complete(resource); + break; + default: + xenidc_gateway_initiator_resource_invalid_stimulus + (resource, stimulus); + break; + } + break; + case xenidc_gateway_initiator_resource_state_i_st_ts: + switch (stimulus) { + case xenidc_gateway_initiator_resource_stimulus_ab: + break; + case xenidc_gateway_initiator_resource_stimulus_sc: + resource->state = + xenidc_gateway_initiator_resource_state_i; + xenidc_gateway_initiator_resource_complete(resource); + break; + default: + xenidc_gateway_initiator_resource_invalid_stimulus + (resource, stimulus); + break; + } + break; + default: + xenidc_gateway_initiator_resource_invalid_stimulus + (resource, stimulus); + break; + } +} + +static void xenidc_gateway_initiator_resource_invalid_stimulus + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway_initiator_resource_stimulus stimulus) { + trace(); + + printk + (KERN_ERR "xenidc: gateway initiator resource %p in state %d" + "received invalid stimulus %d", + resource, resource->state, stimulus); +} + +static void xenidc_gateway_initiator_resource_set_aborted + (xenidc_gateway_initiator_resource * resource) { + trace(); + + resource->error = resource->aborted_error; +} + +static void xenidc_gateway_initiator_resource_complete + (xenidc_gateway_initiator_resource * resource) { + trace(); + + xenidc_callback_complete(&resource->header->callback, resource->error); + + xenidc_callback_success(&resource->callback); +} diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h --- /dev/null Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h Sun Nov 20 17:45:16 2005 @@ -0,0 +1,78 @@ +#ifndef _XENIDC_GATEWAY_INITIATOR_RESOURCE_H +#define _XENIDC_GATEWAY_INITIATOR_RESOURCE_H + +#include +#include +#include +#include "xenidc_gateway_ring.h" + +typedef enum { + xenidc_gateway_initiator_resource_state_i, + xenidc_gateway_initiator_resource_state_i_sm, + xenidc_gateway_initiator_resource_state_i_st, + xenidc_gateway_initiator_resource_state_i_st_ab, + xenidc_gateway_initiator_resource_state_i_st_sc, + xenidc_gateway_initiator_resource_state_i_st_ts +} xenidc_gateway_initiator_resource_state; + +typedef enum { + xenidc_gateway_initiator_resource_stimulus_sm, /* Start message */ + xenidc_gateway_initiator_resource_stimulus_st, /* Start transaction */ + xenidc_gateway_initiator_resource_stimulus_ab, /* Abort */ + xenidc_gateway_initiator_resource_stimulus_sc, /* Send complete */ + xenidc_gateway_initiator_resource_stimulus_ts, /* Transaction status */ +} xenidc_gateway_initiator_resource_stimulus; + +struct xenidc_gateway_initiator_resource_struct { + xenidc_callback callback; + xenidc_gateway *gateway; + int id; + spinlock_t lock; + xenidc_gateway_initiator_resource_state state; + xenidc_gateway_message_and_transaction_header *header; + xenidc_error aborted_error; + xenidc_error error; + xenidc_channel_message channel_message; + xenidc_local_buffer_reference element_lbr; + xenidc_concatenate_base base; + union { + xenidc_gateway_parameters_ring_element parameters_element; + xenidc_gateway_message_ring_element message_element; + }; +}; + +#define XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK + +static inline struct list_head *xenidc_gateway_initiator_resource_to_link + (xenidc_gateway_initiator_resource * resource) { + return &resource->XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK; +} + +static inline xenidc_gateway_initiator_resource + *xenidc_gateway_initiator_resource_callback_to(xenidc_callback * callback) +{ + return container_of + (callback, xenidc_gateway_initiator_resource, callback); +} + +static inline xenidc_gateway *xenidc_gateway_initiator_resource_query_gateway + (xenidc_gateway_initiator_resource * resource) { + return resource->gateway; +} + +void xenidc_gateway_initiator_resource_init + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway * gateway, xenidc_callback_function callback, int id); + +void xenidc_gateway_initiator_resource_start + (xenidc_gateway_initiator_resource * resource, + xenidc_gateway_message_and_transaction_header * header); + +void xenidc_gateway_initiator_resource_abort + (xenidc_gateway_initiator_resource * resource, xenidc_error error); + +int xenidc_gateway_initiator_resource_handle_status + (xenidc_gateway_initiator_resource * resource, + xenidc_error error, xenidc_local_buffer_reference status); + +#endif diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h --- /dev/null Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h Sun Nov 20 17:45:16 2005 @@ -0,0 +1,65 @@ +/*****************************************************************************/ +/* Xen inter-domain communication gateway ring structure definitions. */ +/* */ +/* 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_GATEWAY_RING_H +#define _XENIDC_GATEWAY_RING_H + +#include + +typedef struct xenidc_gateway_ring_element_header_struct + xenidc_gateway_ring_element_header; + +struct xenidc_gateway_ring_element_header_struct { + u8 type; + u8 reserved[7]; +}; + +#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE 0 +#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS 1 +#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS 2 + +typedef struct xenidc_gateway_message_ring_element_struct + xenidc_gateway_message_ring_element; + +struct xenidc_gateway_message_ring_element_struct { + xenidc_gateway_ring_element_header header; +}; + +typedef struct xenidc_gateway_parameters_ring_element_struct + xenidc_gateway_parameters_ring_element; + +struct xenidc_gateway_parameters_ring_element_struct { + xenidc_gateway_ring_element_header header; + u32 id; + u16 status_byte_count; + u16 reserved; +}; + +typedef struct xenidc_gateway_status_ring_element_struct + xenidc_gateway_status_ring_element; + +struct xenidc_gateway_status_ring_element_struct { + xenidc_gateway_ring_element_header header; + u32 id; + xenidc_error error; +}; + +#endif diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c --- /dev/null Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c Sun Nov 20 17:45:16 2005 @@ -0,0 +1,190 @@ +/*****************************************************************************/ +/* The xenidc_gateway_target_resource object performs the target-side part */ +/* of the processing of a client message or transaction sent across the */ +/* gateway. */ +/* */ +/* 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 */ +/* */ +/*****************************************************************************/ + +#include +#include "xenidc_gateway_target_resource.h" +#include "xenidc_trace.h" + +extern void xenidc_gateway_submit_channel_message + (xenidc_gateway * gateway, xenidc_channel_message * message); + +extern void xenidc_gateway_submit_message_to_client + (xenidc_gateway * gateway, xenidc_gateway_message * message); + +extern void xenidc_gateway_submit_transaction_to_client + (xenidc_gateway * gateway, xenidc_gateway_transaction * transaction); + +static void xenidc_gateway_target_resource_channel_message_callback + (xenidc_callback * callback); + +void xenidc_gateway_target_resource_init + (xenidc_gateway_target_resource * resource, + xenidc_gateway * gateway, + xenidc_callback_function callback, xenidc_local_buffer_reference buffer) { + trace(); + + xenidc_callback_init(&resource->callback, callback); + + resource->gateway = gateway; + + resource->buffer = buffer; + + xenidc_callback_init + (xenidc_channel_message_to_callback(&resource->channel_message), + xenidc_gateway_target_resource_channel_message_callback); + + resource->element_lbr = xenidc_vaddress_create_lbr + (&resource->status_element, sizeof(resource->status_element)); + + memset(&resource->status_element, 0, sizeof(resource->status_element)); + + resource->status_element.header.type = + XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS; +} + +static void xenidc_gateway_target_resource_message_callback + (xenidc_callback * callback); + +void xenidc_gateway_target_resource_start_message + (xenidc_gateway_target_resource * resource, + xenidc_local_buffer_reference message_lbr) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + xenidc_gateway_message_init + (&resource->message, + xenidc_gateway_target_resource_message_callback); + + { + xenidc_local_buffer_reference lbr = resource->buffer; + + xenidc_local_buffer_reference_truncate + (&lbr, + xenidc_local_buffer_reference_copy(&lbr, &message_lbr) + ); + + resource->message.message_lbr = lbr; + } + + xenidc_gateway_submit_message_to_client + (resource->gateway, &resource->message); +} + +static void xenidc_gateway_target_resource_message_callback + (xenidc_callback * callback) { + trace(); + + { + xenidc_gateway_target_resource *resource = container_of + (xenidc_gateway_message_callback_to(callback), + xenidc_gateway_target_resource, + message); + + xenidc_callback_success(&resource->callback); + } +} + +static void xenidc_gateway_target_resource_transaction_callback + (xenidc_callback * callback); + +void xenidc_gateway_target_resource_start_transaction + (xenidc_gateway_target_resource * resource, + u32 id, + xenidc_local_buffer_reference parameters_lbr, + xenidc_buffer_byte_count status_byte_count) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + xenidc_gateway_transaction_init + (&resource->transaction, + xenidc_gateway_target_resource_transaction_callback); + + { + xenidc_local_buffer_reference lbr = resource->buffer; + + xenidc_local_buffer_reference_truncate + (&lbr, + xenidc_local_buffer_reference_copy(&lbr, ¶meters_lbr) + ); + + resource->transaction.parameters_lbr = lbr; + } + + { + xenidc_local_buffer_reference lbr = resource->buffer; + + xenidc_local_buffer_reference_subrange + (&lbr, + xenidc_local_buffer_reference_query_byte_count + (¶meters_lbr), status_byte_count); + + xenidc_local_buffer_reference_zero(&lbr); + + resource->transaction.status_lbr = lbr; + } + + resource->status_element.id = id; + + xenidc_gateway_submit_transaction_to_client + (resource->gateway, &resource->transaction); +} + +static void xenidc_gateway_target_resource_transaction_callback + (xenidc_callback * callback) { + trace(); + + { + xenidc_gateway_target_resource *resource = container_of + (xenidc_gateway_transaction_callback_to(callback), + xenidc_gateway_target_resource, + transaction); + + resource->status_element.error = + xenidc_callback_query_error(callback); + + resource->channel_message.message_lbr = + xenidc_concatenate_create_lbr(&resource->base, + &resource->element_lbr, + &resource->transaction. + status_lbr); + + xenidc_gateway_submit_channel_message + (resource->gateway, &resource->channel_message); + } +} + +static void xenidc_gateway_target_resource_channel_message_callback + (xenidc_callback * callback) { + trace(); + + { + xenidc_gateway_target_resource *resource = container_of + (callback, + xenidc_gateway_target_resource, + channel_message.callback); + + xenidc_callback_success(&resource->callback); + } +} diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h --- /dev/null Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h Sun Nov 20 17:45:16 2005 @@ -0,0 +1,79 @@ +/*****************************************************************************/ +/* The xenidc_gateway_target_resource object performs the target-side part */ +/* of the processing of a client message or transaction sent across the */ +/* gateway. */ +/* */ +/* 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_GATEWAY_TARGET_RESOURCE_H +#define _XENIDC_GATEWAY_TARGET_RESOURCE_H + +#include +#include +#include +#include "xenidc_gateway_ring.h" + +struct xenidc_gateway_target_resource_struct { + xenidc_callback callback; + xenidc_gateway *gateway; + xenidc_local_buffer_reference buffer; + union { + xenidc_gateway_message message; + xenidc_gateway_transaction transaction; + }; + xenidc_channel_message channel_message; + xenidc_local_buffer_reference element_lbr; + xenidc_concatenate_base base; + xenidc_gateway_status_ring_element status_element; +}; + +#define XENIDC_GATEWAY_TARGET_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK + +static inline struct list_head *xenidc_gateway_target_resource_to_link + (xenidc_gateway_target_resource * resource) { + return &resource->XENIDC_GATEWAY_TARGET_RESOURCE_LINK; +} + +static inline xenidc_gateway_target_resource + *xenidc_gateway_target_resource_callback_to(xenidc_callback * callback) +{ + return container_of(callback, xenidc_gateway_target_resource, callback); +} + +static inline xenidc_gateway *xenidc_gateway_target_resource_query_gateway + (xenidc_gateway_target_resource * resource) { + return resource->gateway; +} + +extern void xenidc_gateway_target_resource_init + (xenidc_gateway_target_resource * resource, + xenidc_gateway * gateway, + xenidc_callback_function callback, xenidc_local_buffer_reference buffer); + +extern void xenidc_gateway_target_resource_start_message + (xenidc_gateway_target_resource * resource, + xenidc_local_buffer_reference message_lbr); + +extern void xenidc_gateway_target_resource_start_transaction + (xenidc_gateway_target_resource * resource, + u32 id, + xenidc_local_buffer_reference parameters_lbr, + xenidc_buffer_byte_count status_byte_count); + +#endif diff -r 1786d40e66b8 -r b4eca2889318 linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h --- /dev/null Sun Nov 20 17:45:04 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h Sun Nov 20 17:45:16 2005 @@ -0,0 +1,254 @@ +/*****************************************************************************/ +/* Xen inter-domain communication gateway class. This class uses the message */ +/* channel service provided by a xenidc_channel to implement a gateway */ +/* service which allows the client to send both messages and transactions */ +/* (consisting of parameters and status) between domains. */ +/* */ +/* 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_GATEWAY_H +#define _XENIDC_GATEWAY_H + +#include +#include +#include + +typedef struct xenidc_gateway_initiator_resource_struct + xenidc_gateway_initiator_resource; + +typedef struct xenidc_gateway_target_resource_struct + xenidc_gateway_target_resource; + +/* Messages and transactions share a common header because relative order is */ +/* preserved on submission and so they are queued on the same list. */ + +typedef struct xenidc_gateway_message_and_transaction_header_struct + xenidc_gateway_message_and_transaction_header; + +struct xenidc_gateway_message_and_transaction_header_struct { + xenidc_callback callback; + int transaction_not_message; +}; + +#define XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK \ +callback.XENIDC_CALLBACK_LINK + +static inline struct list_head + *xenidc_gateway_message_and_transaction_header_to_link + (xenidc_gateway_message_and_transaction_header * header) { + return xenidc_callback_to_link(&header->callback); +} + +static inline xenidc_callback + *xenidc_gateway_message_and_transaction_header_to_callback + (xenidc_gateway_message_and_transaction_header * header) { + return &header->callback; +} + +/* A xenidc_gateway_message is used to send a message from the local domain */ +/* to the remote domain using the gateway. This is also the structure used */ +/* by the gateway to pass a message to the client. The receiver gets to */ +/* hold onto the message as long as necessary and completes the callback to */ +/* return it when finished with it. */ + +typedef struct xenidc_gateway_message_struct xenidc_gateway_message; + +struct xenidc_gateway_message_struct { + xenidc_gateway_message_and_transaction_header header; + xenidc_local_buffer_reference message_lbr; +}; + +static inline xenidc_callback *xenidc_gateway_message_to_callback + (xenidc_gateway_message * message) { + return &message->header.callback; +} + +static inline xenidc_gateway_message *xenidc_gateway_message_callback_to + (xenidc_callback * callback) { + return container_of(callback, xenidc_gateway_message, header.callback); +} + +static inline struct list_head *xenidc_gateway_message_to_link + (xenidc_gateway_message * message) { + return xenidc_callback_to_link(&message->header.callback); +} + +static inline xenidc_gateway_message *xenidc_gateway_message_link_to + (struct list_head *link) { + return xenidc_gateway_message_callback_to + (xenidc_callback_link_to(link)); +} + +static inline xenidc_gateway_message *xenidc_gateway_message_header_to + (xenidc_gateway_message_and_transaction_header * header) { + return container_of(header, xenidc_gateway_message, header); +} + +static inline void xenidc_gateway_message_init + (xenidc_gateway_message * message, xenidc_callback_function * callback) { + xenidc_callback_init + (xenidc_gateway_message_to_callback(message), callback); + + message->header.transaction_not_message = 0; +} + +/* A xenidc_gateway_transaction is used to send a transaction to the remote */ +/* domain from the local domain. The transaction passes parameters to the */ +/* remote domain and gets status back from the remote domain. */ +/* The structure is used for both sending transactions and when inbound */ +/* transactions are received. The target domain completes the transaction */ +/* with a xenidc_error which is returned to the transaction initiator as the */ +/* error of the callback of the initiators transaction. */ + +typedef struct xenidc_gateway_transaction_struct xenidc_gateway_transaction; + +struct xenidc_gateway_transaction_struct { + xenidc_gateway_message_and_transaction_header header; + xenidc_local_buffer_reference parameters_lbr; + xenidc_local_buffer_reference status_lbr; +}; + +#define XENIDC_GATEWAY_TRANSACTION_LINK header.callback.XENIDC_CALLBACK_LINK + +static inline xenidc_callback *xenidc_gateway_transaction_to_callback + (xenidc_gateway_transaction * transaction) { + return &transaction->header.callback; +} + +static inline xenidc_gateway_transaction + *xenidc_gateway_transaction_callback_to(xenidc_callback * callback) +{ + return container_of + (callback, xenidc_gateway_transaction, header.callback); +} + +static inline struct list_head *xenidc_gateway_transaction_to_link + (xenidc_gateway_transaction * transaction) { + return xenidc_callback_to_link + (xenidc_gateway_transaction_to_callback(transaction)); +} + +static inline xenidc_gateway_transaction *xenidc_gateway_transaction_link_to + (struct list_head *link) { + return xenidc_gateway_transaction_callback_to + (xenidc_callback_link_to(link)); +} + +static inline xenidc_gateway_transaction *xenidc_gateway_transaction_header_to + (xenidc_gateway_message_and_transaction_header * header) { + return container_of(header, xenidc_gateway_transaction, header); +} + +static inline void xenidc_gateway_transaction_init + (xenidc_gateway_transaction * transaction, + xenidc_callback_function * callback) { + xenidc_callback_init + (xenidc_gateway_transaction_to_callback(transaction), callback); + + transaction->header.transaction_not_message = 1; +} + +typedef enum { + xenidc_gateway_state_i, + xenidc_gateway_state_i_cc, + xenidc_gateway_state_i_cc_cd, + xenidc_gateway_state_i_cc_lc, + xenidc_gateway_state_i_cc_cd_lc, + xenidc_gateway_state_i_cc_lc_cd, + xenidc_gateway_state_i_cc_lc_cd_km, + xenidc_gateway_state_i_cc_cd_lc_lg, + xenidc_gateway_state_i_cc_cd_lc_ld, + xenidc_gateway_state_i_cc_cd_lc_lg_ld, + xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti +} xenidc_gateway_state; + +typedef struct xenidc_gateway_struct xenidc_gateway; + +struct xenidc_gateway_struct { + xenidc_channel *channel; + void (*connect) (xenidc_gateway * gateway); + void (*handle_message) + (xenidc_gateway * gateway, xenidc_gateway_message * message); + void (*handle_transaction) + (xenidc_gateway * gateway, xenidc_gateway_transaction * transaction); + void (*disconnect) + (xenidc_gateway * gateway, xenidc_callback * callback); + + u32 initiator_quota; + u32 target_quota; + xenidc_buffer_byte_count target_maximum_byte_count; + + struct list_head initiator_resource_list; + xenidc_gateway_initiator_resource *initiator_resources; + + struct list_head target_resource_list; + xenidc_gateway_target_resource *target_resources; + + spinlock_t lock; + + xenidc_gateway_state state; + + struct list_head message_and_transaction_list; + struct list_head channel_message_list; + + xenidc_work kick_messages_and_transactions_1_work; + xenidc_work kick_channel_messages_1_work; + xenidc_work connect_client_1_work; + xenidc_work disconnect_client_1_work; + xenidc_callback disconnect_client_2_callback; + + int kick_messages_and_transactions_out:1; + int kick_channel_messages_out:1; + u32 initiator_resources_out; + u32 target_resources_out; + + xenidc_callback *channel_disconnect_callback; +}; + +/* Initialised with underlying channel to use to send inter-domain messages */ +/* and client's callbacks and required quotas. */ + +extern int xenidc_gateway_init + (xenidc_gateway * gateway, + xenidc_channel * channel, + void (*connect) (xenidc_gateway * gateway), void (*handle_message) + (xenidc_gateway * gateway, xenidc_gateway_message * message), + void (*handle_transaction) + (xenidc_gateway * gateway, xenidc_gateway_transaction * transaction), + void (*disconnect) + (xenidc_gateway * gateway, xenidc_callback * callback), + u32 initiator_quota, + xenidc_buffer_byte_count initiator_maximum_byte_count, + u32 target_quota, xenidc_buffer_byte_count target_maximum_byte_count); + +/* Called by client between connect and disconnect callback to submit a */ +/* message. */ + +extern void xenidc_gateway_submit_message + (xenidc_gateway * gateway, xenidc_gateway_message * message); + +/* Called by client between connect and disconnect callback to submit a */ +/* transaction. */ + +extern void xenidc_gateway_submit_transaction + (xenidc_gateway * gateway, xenidc_gateway_transaction * transaction); + +extern void xenidc_gateway_exit(xenidc_gateway * gateway); + +#endif