diff -r d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Fri Nov 25 14:47:05 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 d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c --- /dev/null Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c Fri Nov 25 14:47:05 2005 @@ -0,0 +1,937 @@ +/*****************************************************************************/ +/* 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 "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 msgs and tras 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(struct xenidc_gateway *gateway, +xenidc_gateway_stimulus stimulus); + +static void xenidc_gateway_channel_connect(void *context); + +static void +xenidc_gateway_handle_channel_message(void *context, +struct xenidc_channel_message *message); + +static void +xenidc_gateway_channel_disconnect(void *context, +struct xenidc_callback *callback); + +static int +xenidc_gateway_init_or_exit(struct xenidc_gateway *gateway, int exit); + +int +xenidc_gateway_init(struct xenidc_gateway *gateway, +struct xenidc_channel *channel, xenidc_gateway_connect_function *connect, +xenidc_gateway_handle_message_function *handle_message, +xenidc_gateway_handle_transaction_function *handle_transaction, +xenidc_gateway_disconnect_function *disconnect, 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_msgs_and_tras_1(void *data); + +static void +xenidc_gateway_kick_msgs_and_tras_2(struct xenidc_callback *callback); + +static void xenidc_gateway_kick_channel_messages_1(void *data); + +static void +xenidc_gateway_kick_channel_messages_2(struct 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(struct xenidc_callback *callback); + +static int +xenidc_gateway_init_or_exit(struct xenidc_gateway *gateway, int exit) +{ + int return_value = 0; + u32 i; + trace(); + if (exit) + goto exit_path; + INIT_LIST_HEAD(&gateway->initiator_resource_list); + if (gateway->initiator_quota != 0) { + /*FIXME: kmalloc > page size*/ + gateway->initiator_resources = kmalloc(sizeof( + struct xenidc_gateway_initiator_resource) * + gateway->initiator_quota, GFP_KERNEL); + if (gateway->initiator_resources == NULL) { + trace_info("failed to allocate initiator resources"); + return_value = -ENOMEM; + goto exit_no_initiator_resources; + } + for (i = 0; i < gateway->initiator_quota; i++) { + struct xenidc_gateway_initiator_resource *resource = + &gateway->initiator_resources[i]; + xenidc_gateway_initiator_resource_init(resource, + gateway, + xenidc_gateway_kick_msgs_and_tras_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) { + struct xenidc_lbr buffer_area; + gateway->target_resources = kmalloc((sizeof( + struct xenidc_gateway_target_resource) * + gateway->target_quota) + + (gateway->target_maximum_byte_count * + gateway->target_quota), GFP_KERNEL); + if (gateway->target_resources == NULL) { + trace_info("failed to allocate target resources"); + return_value = -ENOMEM; + goto exit_no_target_resources; + } + buffer_area = xenidc_vaddress_create_lbr( + &gateway->target_resources[gateway->target_quota], + gateway->target_maximum_byte_count * + gateway->target_quota); + for (i = 0; i < gateway->target_quota; i++) { + struct xenidc_gateway_target_resource *resource = + &gateway->target_resources[i]; + struct xenidc_lbr buffer = buffer_area; + xenidc_lbr_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_lbr_advance(&buffer_area, + gateway->target_maximum_byte_count); + } + } + spin_lock_init(&gateway->lock); + gateway->state = xenidc_gateway_state_i; + INIT_LIST_HEAD(&gateway->msg_and_tra_list); + INIT_LIST_HEAD(&gateway->channel_message_list); + xenidc_work_init(&gateway->kick_msgs_and_tras_1_work, + xenidc_gateway_kick_msgs_and_tras_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_msgs_and_tras_out = 0; + gateway->kick_channel_messages_out = 0; + gateway->initiator_resources_out = 0; + gateway->target_resources_out = 0; + return 0; + exit_path: + if (gateway->target_quota != 0) { + kfree(gateway->target_resources); + } + exit_no_target_resources: + if (gateway->initiator_quota != 0) { + kfree(gateway->initiator_resources); + } + exit_no_initiator_resources: + return return_value; +} + +void +xenidc_gateway_submit_message(struct xenidc_gateway *gateway, +struct xenidc_gateway_message *message) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + unsigned long flags; + trace(); + spin_lock_irqsave(&gateway->lock, flags); + list_add_tail(xenidc_gateway_message_to_link(message), + &gateway->msg_and_tra_list); + xenidc_gateway_handle_stimulus(gateway, xenidc_gateway_stimulus_mt); + spin_unlock_irqrestore(&gateway->lock, flags); +} + +void +xenidc_gateway_submit_transaction(struct xenidc_gateway *gateway, +struct xenidc_gateway_transaction *transaction) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + unsigned long flags; + trace(); + spin_lock_irqsave(&gateway->lock, flags); + list_add_tail(xenidc_gateway_transaction_to_link(transaction), + &gateway->msg_and_tra_list); + xenidc_gateway_handle_stimulus(gateway, xenidc_gateway_stimulus_mt); + spin_unlock_irqrestore(&gateway->lock, flags); +} + +void xenidc_gateway_exit(struct xenidc_gateway *gateway) +{ + trace(); + (void)xenidc_gateway_init_or_exit(gateway, 1); +} + +static void xenidc_gateway_channel_connect(void *context) +{ + struct xenidc_gateway *gateway = (struct xenidc_gateway *) context; + unsigned long flags; + trace(); + 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, +struct xenidc_channel_message *message) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct xenidc_gateway *gateway = (struct xenidc_gateway *)context; + struct xenidc_gateway_ring_element_header header; + trace(); + if (xenidc_lbr_copy_out(&message->message_lbr, + &header, sizeof(header)) != sizeof(header)) + goto protocol_error; + if (header.type == XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS) { + struct xenidc_lbr status_lbr = message->message_lbr; + struct xenidc_gateway_status_ring_element status_element; + struct xenidc_gateway_initiator_resource *resource; + if (xenidc_lbr_copy_out(&status_lbr, &status_element, + sizeof(status_element)) != sizeof(status_element)) + goto protocol_error; + xenidc_lbr_advance(&status_lbr, sizeof(status_element)); + if (status_element.id >= gateway->initiator_quota) + goto protocol_error; + 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, +struct xenidc_callback *callback) +{ + struct xenidc_gateway *gateway = (struct xenidc_gateway *)context; + unsigned long flags; + trace(); + 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(struct xenidc_gateway *gateway, +struct xenidc_channel_message *message) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + xenidc_channel_submit_message(gateway->channel, message); +} + +void +xenidc_gateway_submit_message_to_client(struct xenidc_gateway *gateway, +struct xenidc_gateway_message *message) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + gateway->handle_message(gateway, message); +} + +void +xenidc_gateway_submit_transaction_to_client(struct xenidc_gateway *gateway, +struct xenidc_gateway_transaction *transaction) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + gateway->handle_transaction(gateway, transaction); +} + +static void +xenidc_gateway_invalid_stimulus(struct xenidc_gateway *gateway, +xenidc_gateway_stimulus stimulus); +static void +xenidc_gateway_kick_msgs_and_tras(struct xenidc_gateway *gateway); +static void +xenidc_gateway_fail_out_msgs_and_tras(struct xenidc_gateway *gateway); +static void +xenidc_gateway_kick_channel_messages(struct xenidc_gateway *gateway); +static void +xenidc_gateway_complete_channel_messages(struct xenidc_gateway *gateway); +static void +xenidc_gateway_connect_client(struct xenidc_gateway *gateway); +static void +xenidc_gateway_disconnect_client(struct xenidc_gateway *gateway); +static void +xenidc_gateway_abort_initiator_resources(struct xenidc_gateway *gateway); +static void +xenidc_gateway_test_initiator_resources(struct xenidc_gateway *gateway); +static void +xenidc_gateway_test_target_resources(struct xenidc_gateway *gateway); +static void +xenidc_gateway_complete_channel_disconnect(struct xenidc_gateway *gateway); + +static void +xenidc_gateway_handle_stimulus(struct xenidc_gateway *gateway, +xenidc_gateway_stimulus stimulus) +{ + trace_info("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_msgs_and_tras(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_msgs_and_tras(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_msgs_and_tras(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_msgs_and_tras(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_msgs_and_tras + (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(struct 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_msgs_and_tras(struct xenidc_gateway *gateway) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + if (!gateway->kick_msgs_and_tras_out) { + gateway->kick_msgs_and_tras_out = 1; + (void)xenidc_work_schedule(&gateway-> + kick_msgs_and_tras_1_work); + } +} + +static void xenidc_gateway_kick_msgs_and_tras_1(void *data) +{ + struct xenidc_gateway *gateway = (struct xenidc_gateway *)data; + unsigned long flags; + trace(); + spin_lock_irqsave(&gateway->lock, flags); + while ((!list_empty(&gateway->msg_and_tra_list)) && + (!list_empty(&gateway->initiator_resource_list))) { + struct xenidc_gateway_msg_and_tra_header *header; + struct xenidc_gateway_initiator_resource *resource; + header = list_entry(gateway->msg_and_tra_list.next, + struct xenidc_gateway_msg_and_tra_header, + XENIDC_GATEWAY_MSG_AND_TRA_HEADER_LINK); + resource = list_entry(gateway->initiator_resource_list.next, + struct xenidc_gateway_initiator_resource, + XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK); + list_del_init(xenidc_gateway_msg_and_tra_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_msgs_and_tras_out = 0; + xenidc_gateway_handle_stimulus(gateway, xenidc_gateway_stimulus_km); + spin_unlock_irqrestore(&gateway->lock, flags); +} + +static void +xenidc_gateway_kick_msgs_and_tras_2(struct xenidc_callback *callback) +{ + struct xenidc_gateway_initiator_resource *resource = + xenidc_gateway_initiator_resource_callback_to(callback); + struct xenidc_gateway *gateway = + xenidc_gateway_initiator_resource_query_gateway(resource); + unsigned long flags; + trace(); + 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_msgs_and_tras(struct xenidc_gateway *gateway) +{ + trace(); + while (!list_empty(&gateway->msg_and_tra_list)) { + struct xenidc_gateway_msg_and_tra_header *header = list_entry( + gateway->msg_and_tra_list.next, + struct xenidc_gateway_msg_and_tra_header, + XENIDC_GATEWAY_MSG_AND_TRA_HEADER_LINK); + list_del_init(xenidc_gateway_msg_and_tra_header_to_link( + header)); + xenidc_callback_complete( + xenidc_gateway_msg_and_tra_header_to_callback(header), + XENIDC_ERROR_DISCONNECT); + } +} + +static void +xenidc_gateway_kick_channel_messages(struct xenidc_gateway *gateway) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + 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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct xenidc_gateway *gateway = (struct xenidc_gateway *)data; + unsigned long flags; + trace(); + spin_lock_irqsave(&gateway->lock, flags); + while ((!list_empty(&gateway->channel_message_list)) && + (!list_empty(&gateway->target_resource_list))) { + struct xenidc_channel_message *message; + struct xenidc_gateway_target_resource *resource; + struct xenidc_gateway_ring_element_header header; + message = list_entry(gateway->channel_message_list.next, + struct xenidc_channel_message, + XENIDC_CHANNEL_MESSAGE_LINK); + resource = list_entry(gateway->target_resource_list.next, + struct xenidc_gateway_target_resource, + XENIDC_GATEWAY_TARGET_RESOURCE_LINK); + list_del_init(xenidc_channel_message_to_link(message)); + if (xenidc_lbr_copy_out(&message->message_lbr, &header, + sizeof(header)) != sizeof(header)) + goto protocol_error; + if (header.type == XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE) { + struct xenidc_lbr message_lbr = message->message_lbr; + xenidc_lbr_advance(&message_lbr, sizeof( + struct 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) { + struct xenidc_lbr parameters_lbr = + message->message_lbr; + struct xenidc_gateway_parameters_ring_element + parameters_element; + if (xenidc_lbr_copy_out(¶meters_lbr, + ¶meters_element, + sizeof(parameters_element)) != sizeof( + parameters_element)) + goto protocol_error; + xenidc_lbr_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(struct xenidc_callback *callback) +{ + struct xenidc_gateway_target_resource *resource = + xenidc_gateway_target_resource_callback_to(callback); + struct xenidc_gateway *gateway = + xenidc_gateway_target_resource_query_gateway(resource); + unsigned long flags; + trace(); + 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( +struct xenidc_gateway *gateway) +{ + trace(); + while (!list_empty(&gateway->channel_message_list)) { + struct xenidc_channel_message *message = list_entry( + gateway->channel_message_list.next, + struct 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(struct xenidc_gateway *gateway) +{ + trace(); + (void)xenidc_work_schedule(&gateway->connect_client_1_work); +} + +static void xenidc_gateway_connect_client_1(void *data) +{ + struct xenidc_gateway *gateway = (struct xenidc_gateway *)data; + unsigned long flags; + trace(); + gateway->connect(gateway); + 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(struct xenidc_gateway *gateway) +{ + trace(); + (void)xenidc_work_schedule(&gateway->disconnect_client_1_work); +} + +static void xenidc_gateway_disconnect_client_1(void *data) +{ + struct xenidc_gateway *gateway = (struct xenidc_gateway *)data; + unsigned long flags; + trace(); + gateway->disconnect(gateway, &gateway->disconnect_client_2_callback); + 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(struct xenidc_callback *callback) +{ + struct xenidc_gateway *gateway = container_of(callback, + struct xenidc_gateway, + disconnect_client_2_callback); + unsigned long flags; + trace(); + 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(struct xenidc_gateway *gateway) +{ + u32 i; + trace(); + 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(struct 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(struct 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(struct xenidc_gateway *gateway) +{ + trace(); + xenidc_callback_success(gateway->channel_disconnect_callback); +} diff -r d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c --- /dev/null Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c Fri Nov 25 14:47:05 2005 @@ -0,0 +1,346 @@ +/*****************************************************************************/ +/* 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" + +void +xenidc_gateway_submit_channel_message(struct xenidc_gateway *gateway, +struct xenidc_channel_message *message); + +static void +xenidc_gateway_initiator_resource_handle_stimulus( +struct xenidc_gateway_initiator_resource *resource, +xenidc_gateway_initiator_resource_stimulus stimulus); + +static void +xenidc_gateway_initiator_resource_channel_message_callback( +struct xenidc_callback *callback); + +void xenidc_gateway_initiator_resource_init( +struct xenidc_gateway_initiator_resource *resource, +struct 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); +} + +static void +xenidc_gateway_initiator_resource_start_transaction( +struct xenidc_gateway_initiator_resource *resource, +struct xenidc_gateway_msg_and_tra_header *header +) +{ + struct xenidc_gateway_transaction *transaction = + xenidc_gateway_transaction_header_to(header); + trace(); + 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_lbr_query_byte_count( + &transaction->status_lbr); +} + +static void +xenidc_gateway_initiator_resource_start_message( +struct xenidc_gateway_initiator_resource *resource, +struct xenidc_gateway_msg_and_tra_header *header +) +{ + struct xenidc_gateway_message *message = + xenidc_gateway_message_header_to(header); + trace(); + 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; +} + +void +xenidc_gateway_initiator_resource_start( +struct xenidc_gateway_initiator_resource *resource, +struct xenidc_gateway_msg_and_tra_header *header +) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + xenidc_gateway_initiator_resource_stimulus stimulus; + unsigned long flags; + trace(); + resource->header = header; + resource->error = XENIDC_ERROR_SUCCESS; + if (header->transaction_not_message) { + xenidc_gateway_initiator_resource_start_transaction( resource, + header ); + stimulus = xenidc_gateway_initiator_resource_stimulus_st; + } else { + xenidc_gateway_initiator_resource_start_message( resource, + header ); + stimulus = xenidc_gateway_initiator_resource_stimulus_sm; + } + 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( +struct xenidc_gateway_initiator_resource *resource, +xenidc_error error) +{ + unsigned long flags; + trace(); + 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( +struct xenidc_callback *callback) +{ + struct xenidc_gateway_initiator_resource *resource = container_of( + callback, + struct xenidc_gateway_initiator_resource, + channel_message.callback); + unsigned long flags; + trace(); + 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( +struct xenidc_gateway_initiator_resource *resource, xenidc_error error, +struct xenidc_lbr status_lbr) +{ + int return_value = -1; + unsigned long flags; + trace(); + 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)) { + struct xenidc_gateway_transaction *transaction = + xenidc_gateway_transaction_header_to(resource->header); + if (xenidc_lbr_query_byte_count(&status_lbr) == + xenidc_lbr_query_byte_count(&transaction-> + status_lbr)) { + xenidc_lbr_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( +struct xenidc_gateway_initiator_resource *resource, +xenidc_gateway_initiator_resource_stimulus stimulus); + +static void +xenidc_gateway_initiator_resource_set_aborted( +struct xenidc_gateway_initiator_resource *resource); + +static void +xenidc_gateway_initiator_resource_complete( +struct xenidc_gateway_initiator_resource *resource); + +static void +xenidc_gateway_initiator_resource_handle_stimulus( +struct xenidc_gateway_initiator_resource *resource, +xenidc_gateway_initiator_resource_stimulus stimulus) +{ + trace_info("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( +struct 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( +struct xenidc_gateway_initiator_resource *resource) +{ + trace(); + resource->error = resource->aborted_error; +} + +static void xenidc_gateway_initiator_resource_complete( +struct xenidc_gateway_initiator_resource *resource) +{ + trace(); + xenidc_callback_complete(&resource->header->callback, resource->error); + xenidc_callback_success(&resource->callback); +} diff -r d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h --- /dev/null Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h Fri Nov 25 14:47:05 2005 @@ -0,0 +1,111 @@ +/*****************************************************************************/ +/* 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 */ +/* */ +/*****************************************************************************/ + +#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, /* Tra. status */ +} xenidc_gateway_initiator_resource_stimulus; + +struct xenidc_gateway_initiator_resource { + struct xenidc_callback callback; + struct xenidc_gateway *gateway; + int id; + spinlock_t lock; + xenidc_gateway_initiator_resource_state state; + struct xenidc_gateway_msg_and_tra_header *header; + xenidc_error aborted_error; + xenidc_error error; + struct xenidc_channel_message channel_message; + struct xenidc_lbr element_lbr; + struct xenidc_concatenate_base base; + union { + struct xenidc_gateway_parameters_ring_element + parameters_element; + struct 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( +struct xenidc_gateway_initiator_resource *resource) +{ + return &resource->XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK; +} + +static inline struct xenidc_gateway_initiator_resource * +xenidc_gateway_initiator_resource_callback_to( +struct xenidc_callback *callback) +{ + return container_of(callback, struct xenidc_gateway_initiator_resource, + callback); +} + +static inline struct xenidc_gateway * +xenidc_gateway_initiator_resource_query_gateway( +struct xenidc_gateway_initiator_resource *resource) +{ + return resource->gateway; +} + +void +xenidc_gateway_initiator_resource_init( +struct xenidc_gateway_initiator_resource *resource, +struct xenidc_gateway *gateway, xenidc_callback_function callback, int id); + +void +xenidc_gateway_initiator_resource_start( +struct xenidc_gateway_initiator_resource *resource, +struct xenidc_gateway_msg_and_tra_header *header); + +void +xenidc_gateway_initiator_resource_abort( +struct xenidc_gateway_initiator_resource *resource, xenidc_error error); + +int +xenidc_gateway_initiator_resource_handle_status( +struct xenidc_gateway_initiator_resource *resource, xenidc_error error, +struct xenidc_lbr status); + +#endif diff -r d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h --- /dev/null Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h Fri Nov 25 14:47:05 2005 @@ -0,0 +1,53 @@ +/*****************************************************************************/ +/* 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 + +struct xenidc_gateway_ring_element_header { + 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 + +struct xenidc_gateway_message_ring_element { + struct xenidc_gateway_ring_element_header header; +}; + +struct xenidc_gateway_parameters_ring_element { + struct xenidc_gateway_ring_element_header header; + u32 id; + u16 status_byte_count; + u16 reserved; +}; + +struct xenidc_gateway_status_ring_element { + struct xenidc_gateway_ring_element_header header; + u32 id; + xenidc_error error; +}; + +#endif diff -r d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c --- /dev/null Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c Fri Nov 25 14:47:05 2005 @@ -0,0 +1,144 @@ +/*****************************************************************************/ +/* 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" + +void +xenidc_gateway_submit_channel_message(struct xenidc_gateway *gateway, +struct xenidc_channel_message *message); + +void xenidc_gateway_submit_message_to_client(struct xenidc_gateway *gateway, +struct xenidc_gateway_message *message); + +void xenidc_gateway_submit_transaction_to_client( +struct xenidc_gateway *gateway, +struct xenidc_gateway_transaction *transaction); + +static void +xenidc_gateway_target_resource_channel_message_callback( +struct xenidc_callback *callback); + +void xenidc_gateway_target_resource_init( +struct xenidc_gateway_target_resource *resource, +struct xenidc_gateway *gateway, xenidc_callback_function callback, +struct xenidc_lbr 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( +struct xenidc_callback *callback); + +void xenidc_gateway_target_resource_start_message( +struct xenidc_gateway_target_resource *resource, struct xenidc_lbr message_lbr) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct xenidc_lbr lbr = resource->buffer; + trace(); + xenidc_gateway_message_init(&resource->message, + xenidc_gateway_target_resource_message_callback); + xenidc_lbr_truncate(&lbr, xenidc_lbr_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( +struct xenidc_callback *callback) +{ + struct xenidc_gateway_target_resource *resource = container_of( + xenidc_gateway_message_callback_to(callback), + struct xenidc_gateway_target_resource, + message); + trace(); + xenidc_callback_success(&resource->callback); +} + +static void +xenidc_gateway_target_resource_transaction_callback( +struct xenidc_callback *callback); + +void +xenidc_gateway_target_resource_start_transaction( +struct xenidc_gateway_target_resource *resource, u32 id, +struct xenidc_lbr parameters_lbr, xenidc_buffer_byte_count status_byte_count) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + xenidc_gateway_transaction_init(&resource->transaction, + xenidc_gateway_target_resource_transaction_callback); + resource->transaction.parameters_lbr = resource->buffer; + xenidc_lbr_truncate(&resource->transaction.parameters_lbr, + xenidc_lbr_copy(&resource->transaction.parameters_lbr, + ¶meters_lbr)); + resource->transaction.status_lbr = resource->buffer; + xenidc_lbr_subrange(&resource->transaction.status_lbr, + xenidc_lbr_query_byte_count(¶meters_lbr), + status_byte_count); + xenidc_lbr_zero(&resource->transaction.status_lbr); + resource->status_element.id = id; + xenidc_gateway_submit_transaction_to_client(resource->gateway, + &resource->transaction); +} + +static void +xenidc_gateway_target_resource_transaction_callback( +struct xenidc_callback *callback) +{ + struct xenidc_gateway_target_resource *resource = container_of( + xenidc_gateway_transaction_callback_to(callback), + struct xenidc_gateway_target_resource, transaction); + trace(); + 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( +struct xenidc_callback *callback) +{ + struct xenidc_gateway_target_resource *resource = container_of( + callback, + struct xenidc_gateway_target_resource, + channel_message.callback); + trace(); + xenidc_callback_success(&resource->callback); +} diff -r d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h --- /dev/null Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h Fri Nov 25 14:47:05 2005 @@ -0,0 +1,85 @@ +/*****************************************************************************/ +/* 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; + struct xenidc_gateway *gateway; + struct xenidc_lbr buffer; + union { + struct xenidc_gateway_message message; + struct xenidc_gateway_transaction transaction; + }; + struct xenidc_channel_message channel_message; + struct xenidc_lbr element_lbr; + struct xenidc_concatenate_base base; + struct 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( +struct xenidc_gateway_target_resource *resource) +{ + return &resource->XENIDC_GATEWAY_TARGET_RESOURCE_LINK; +} + +static inline struct xenidc_gateway_target_resource * +xenidc_gateway_target_resource_callback_to(struct xenidc_callback *callback) +{ + return container_of(callback, struct xenidc_gateway_target_resource, + callback); +} + +static inline struct xenidc_gateway * +xenidc_gateway_target_resource_query_gateway( +struct xenidc_gateway_target_resource *resource) +{ + return resource->gateway; +} + +void +xenidc_gateway_target_resource_init( +struct xenidc_gateway_target_resource *resource, +struct xenidc_gateway *gateway, xenidc_callback_function callback, +struct xenidc_lbr buffer); + +void +xenidc_gateway_target_resource_start_message( +struct xenidc_gateway_target_resource *resource, +struct xenidc_lbr message_lbr); + +void +xenidc_gateway_target_resource_start_transaction( +struct xenidc_gateway_target_resource *resource, u32 id, +struct xenidc_lbr parameters_lbr, xenidc_buffer_byte_count status_byte_count); + +#endif diff -r d2703777cccb -r 3847b32d2cef linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h --- /dev/null Thu Nov 24 18:30:37 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h Fri Nov 25 14:47:05 2005 @@ -0,0 +1,272 @@ +/*****************************************************************************/ +/* 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 + +struct xenidc_gateway_initiator_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. */ + +struct xenidc_gateway_msg_and_tra_header { + struct xenidc_callback callback; + int transaction_not_message; +}; + +#define XENIDC_GATEWAY_MSG_AND_TRA_HEADER_LINK \ +callback.XENIDC_CALLBACK_LINK + +static inline struct list_head * +xenidc_gateway_msg_and_tra_header_to_link( +struct xenidc_gateway_msg_and_tra_header *header) +{ + return xenidc_callback_to_link(&header->callback); +} + +static inline struct xenidc_callback * +xenidc_gateway_msg_and_tra_header_to_callback( +struct xenidc_gateway_msg_and_tra_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. */ + +struct xenidc_gateway_message { + struct xenidc_gateway_msg_and_tra_header header; + struct xenidc_lbr message_lbr; +}; + +static inline struct xenidc_callback * +xenidc_gateway_message_to_callback(struct xenidc_gateway_message *message) +{ + return &message->header.callback; +} + +static inline struct xenidc_gateway_message * +xenidc_gateway_message_callback_to(struct xenidc_callback *callback) +{ + return container_of(callback, struct xenidc_gateway_message, + header.callback); +} + +static inline struct list_head * +xenidc_gateway_message_to_link(struct xenidc_gateway_message *message) +{ + return xenidc_callback_to_link(&message->header.callback); +} + +static inline struct 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 struct xenidc_gateway_message * +xenidc_gateway_message_header_to( +struct xenidc_gateway_msg_and_tra_header *header) +{ + return container_of(header, struct xenidc_gateway_message, header); +} + +static inline void xenidc_gateway_message_init( +struct 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. */ + +struct xenidc_gateway_transaction { + struct xenidc_gateway_msg_and_tra_header header; + struct xenidc_lbr parameters_lbr; + struct xenidc_lbr status_lbr; +}; + +#define XENIDC_GATEWAY_TRANSACTION_LINK header.callback.XENIDC_CALLBACK_LINK + +static inline struct xenidc_callback * +xenidc_gateway_transaction_to_callback( +struct xenidc_gateway_transaction *transaction) +{ + return &transaction->header.callback; +} + +static inline struct xenidc_gateway_transaction * +xenidc_gateway_transaction_callback_to(struct xenidc_callback *callback) +{ + return container_of(callback, struct xenidc_gateway_transaction, + header.callback); +} + +static inline struct list_head * +xenidc_gateway_transaction_to_link( +struct xenidc_gateway_transaction *transaction) +{ + return xenidc_callback_to_link(xenidc_gateway_transaction_to_callback( + transaction)); +} + +static inline struct 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 struct xenidc_gateway_transaction * +xenidc_gateway_transaction_header_to( +struct xenidc_gateway_msg_and_tra_header *header) +{ + return container_of(header, struct xenidc_gateway_transaction, header); +} + +static inline void xenidc_gateway_transaction_init( +struct 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; + +struct xenidc_gateway; + +typedef void xenidc_gateway_connect_function(struct xenidc_gateway *gateway); + +typedef void +xenidc_gateway_handle_message_function(struct xenidc_gateway *gateway, +struct xenidc_gateway_message *message); + +typedef void +xenidc_gateway_handle_transaction_function( +struct xenidc_gateway *gateway, +struct xenidc_gateway_transaction *transaction); + +typedef void +xenidc_gateway_disconnect_function(struct xenidc_gateway *gateway, +struct xenidc_callback *callback); + +struct xenidc_gateway { + struct xenidc_channel *channel; + + xenidc_gateway_connect_function *connect; + xenidc_gateway_handle_message_function *handle_message; + xenidc_gateway_handle_transaction_function *handle_transaction; + xenidc_gateway_disconnect_function *disconnect; + + u32 initiator_quota; + u32 target_quota; + xenidc_buffer_byte_count target_maximum_byte_count; + + struct list_head initiator_resource_list; + struct xenidc_gateway_initiator_resource *initiator_resources; + + struct list_head target_resource_list; + struct xenidc_gateway_target_resource *target_resources; + + spinlock_t lock; + + xenidc_gateway_state state; + + struct list_head msg_and_tra_list; + struct list_head channel_message_list; + + struct xenidc_work kick_msgs_and_tras_1_work; + struct xenidc_work kick_channel_messages_1_work; + struct xenidc_work connect_client_1_work; + struct xenidc_work disconnect_client_1_work; + struct xenidc_callback disconnect_client_2_callback; + + int kick_msgs_and_tras_out:1; + int kick_channel_messages_out:1; + u32 initiator_resources_out; + u32 target_resources_out; + + struct xenidc_callback *channel_disconnect_callback; +}; + +/* Initialised with underlying channel to use to send inter-domain messages */ +/* and client's callbacks and required quotas. */ + +int +xenidc_gateway_init(struct xenidc_gateway *gateway, +struct xenidc_channel *channel, xenidc_gateway_connect_function *connect, +xenidc_gateway_handle_message_function *handle_message, +xenidc_gateway_handle_transaction_function *handle_transaction, +xenidc_gateway_disconnect_function *disconnect, 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. */ + +void +xenidc_gateway_submit_message(struct xenidc_gateway *gateway, +struct xenidc_gateway_message *message); + +/* Called by client between connect and disconnect callback to submit a */ +/* transaction. */ + +extern void +xenidc_gateway_submit_transaction(struct xenidc_gateway *gateway, +struct xenidc_gateway_transaction *transaction); + +extern void +xenidc_gateway_exit(struct xenidc_gateway *gateway); + +#endif