diff -r 60996909c1c7 -r 0331fa2f86c1 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Fri Nov 25 16:10:28 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Fri Nov 25 17:36:38 2005 @@ -16,3 +16,4 @@ xenidc-objs += xenidc_gateway_initiator_resource.o xenidc-objs += xenidc_gateway_target_resource.o xenidc-objs += xenidc_endpoint.o +xenidc-objs += xenidc_rbr_provider_pool.o diff -r 60996909c1c7 -r 0331fa2f86c1 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c --- /dev/null Fri Nov 25 16:10:28 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c Fri Nov 25 17:36:38 2005 @@ -0,0 +1,277 @@ +/*****************************************************************************/ +/* Xen remote buffer reference provider pool. */ +/* */ +/* 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_trace.h" + +static XENIDC_CALLBACK_SERIALISER(callback_serialiser); + +struct xenidc_rbr_provider_pool { + struct xenidc_buffer_resource_list dedicated_resources; + struct xenidc_buffer_resource_provider *provider; + spinlock_t lock; + struct xenidc_buffer_resource_list head_request_req; + struct list_head request_list; + int kicking_requests:1; + int head_request_req_calculated:1; +}; + +static int +xenidc_rbr_provider_pool_init_or_exit(struct xenidc_rbr_provider_pool *pool, +int exit) +{ + int return_value = 0; + trace(); + if (exit) + goto exit_path; + pool->provider = xenidc_allocate_buffer_resource_provider( + pool->dedicated_resources); + if (pool->provider == NULL) + goto exit_no_provider; + spin_lock_init(&pool->lock); + INIT_LIST_HEAD(&pool->request_list); + pool->kicking_requests = 0; + pool->head_request_req_calculated = 0; + return 0; + exit_path: + xenidc_free_buffer_resource_provider(pool->provider); + exit_no_provider: + return return_value; +} + +struct xenidc_rbr_provider_pool * +xenidc_allocate_rbr_provider_pool( +struct xenidc_buffer_resource_list dedicated_resources) +{ + struct xenidc_rbr_provider_pool *pool; + trace(); + pool = (struct xenidc_rbr_provider_pool *)kmalloc(sizeof( + struct xenidc_rbr_provider_pool), GFP_KERNEL); + if (pool != NULL) { + pool->dedicated_resources = dedicated_resources; + if (xenidc_rbr_provider_pool_init_or_exit(pool, 0) != 0) { + kfree(pool); + pool = NULL; + } + } + return pool; +} + +void +xenidc_free_rbr_provider_pool(struct xenidc_rbr_provider_pool *pool) +{ + trace(); + (void)xenidc_rbr_provider_pool_init_or_exit(pool, 1); + kfree(pool); +} + +static void +xenidc_rbr_provider_pool_kick_requests(struct xenidc_rbr_provider_pool *pool); + +void +xenidc_rbr_provider_pool_reserve_and_create_rbrs( +struct xenidc_rbr_provider_pool *pool, +struct xenidc_reserve_and_create_rbr_request *request, +struct xenidc_address address) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + unsigned long flags; + trace(); + request->pool = pool; + request->address = address; + spin_lock_irqsave(&pool->lock, flags); + list_add_tail(xenidc_reserve_and_create_rbr_request_to_link(request), + &pool->request_list); + spin_unlock_irqrestore(&pool->lock, flags); + xenidc_rbr_provider_pool_kick_requests(pool); +} + +static int xenidc_rbr_provider_pool_calc_req( +struct xenidc_reserve_and_create_rbr_request *request, +struct xenidc_buffer_resource_list *list) +{ + struct xenidc_create_rbr_request_element *element; + trace(); + *list = xenidc_buffer_resource_list_null(); + list_for_each_entry(element, &request->request_elements, link) { + struct xenidc_lbr resolved_lbr = xenidc_lbr_resolve( + &element->lbr); + struct xenidc_buffer_resource_list element_list; + if (xenidc_lbr_query_byte_count(&resolved_lbr) != + xenidc_lbr_query_byte_count(&element->lbr)) { + printk(KERN_WARNING "xenidc_rbr_provider_pool resolved" + " a virtual local buffer reference to multiple" + " concrete local buffer references. This is" + " currently unsupported. Sorry.\n"); + return 1; + } + if (xenidc_lbr_calculate_rbr_resources(&resolved_lbr, + &request->address, &element_list) != 0) + return 1; + xenidc_buffer_resource_list_plus_equals(list, &element_list); + } + return 0; +} + +static void +xenidc_rbr_provider_pool_service_request( +struct xenidc_rbr_provider_pool *pool, +struct xenidc_reserve_and_create_rbr_request *request) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct xenidc_create_rbr_request_element *element; + trace(); + list_for_each_entry(element, &request->request_elements, link) { + struct xenidc_lbr resolved_lbr = xenidc_lbr_resolve( + &element->lbr); + element->handle = xenidc_lbr_create_rbr(&resolved_lbr, + &request->address, pool->provider, + &element->rbr, element->access_flags); + } + xenidc_callback_serialiser_complete_callback(&callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_create_callback( + request), + XENIDC_ERROR_SUCCESS); +} + +static void xenidc_rbr_provider_pool_kick_requests( +struct xenidc_rbr_provider_pool *pool) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + unsigned long flags; + trace(); + spin_lock_irqsave(&pool->lock, flags); + while ((!pool->kicking_requests) && + (!list_empty(&pool->request_list))) { + struct xenidc_buffer_resource_list free_resources; + struct xenidc_reserve_and_create_rbr_request *request = + xenidc_reserve_and_create_rbr_request_link_to( + pool->request_list.next); + if (!pool->head_request_req_calculated) { + if ((xenidc_rbr_provider_pool_calc_req(request, + &pool->head_request_req) != 0) || + !xenidc_buffer_resource_list_subset_of( + &pool->head_request_req, + &pool->dedicated_resources)) { + list_del_init( + xenidc_reserve_and_create_rbr_request_to_link( + request)); + xenidc_callback_serialiser_complete_callback( + &callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_create_callback( + request), + XENIDC_ERROR_TOO_BIG); + continue; + } + pool->head_request_req_calculated = 1; + } + free_resources = + xenidc_buffer_resource_provider_query_free_resources( + pool->provider); + if (!xenidc_buffer_resource_list_subset_of( + &pool->head_request_req, &free_resources)) { + trace_info("waiting for resources"); + break; + } + list_del_init(xenidc_reserve_and_create_rbr_request_to_link( + request)); + pool->head_request_req_calculated = 0; + pool->kicking_requests = 1; + spin_unlock_irqrestore(&pool->lock, flags); + xenidc_rbr_provider_pool_service_request(pool, request); + spin_lock_irqsave(&pool->lock, flags); + pool->kicking_requests = 0; + } + spin_unlock_irqrestore(&pool->lock, flags); +} + +void +xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs( +struct xenidc_reserve_and_create_rbr_request *request, xenidc_error error) +{ + struct xenidc_rbr_provider_pool *pool = request->pool; + unsigned long flags; + struct xenidc_reserve_and_create_rbr_request *queued_request; + trace(); + spin_lock_irqsave(&pool->lock, flags); + list_for_each_entry(queued_request, &pool->request_list, + XENIDC_RESERVE_AND_CREATE_RBR_REQUEST_LINK) { + if (request == queued_request) { + list_del_init( + xenidc_reserve_and_create_rbr_request_to_link( + request)); + pool->head_request_req_calculated = 0; + xenidc_callback_serialiser_complete_callback( + &callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_create_callback + (request), error); + break; + } + } + spin_unlock_irqrestore(&pool->lock, flags); +} + +static void +xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1( +struct xenidc_callback *callback); + +void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs( +struct xenidc_reserve_and_create_rbr_request *request) +{ + trace(); + xenidc_callback_init(&request->reserved_callback, + xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1); + xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1( + &request->reserved_callback); +} + +static void +xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1( +struct xenidc_callback *callback) +{ + struct xenidc_reserve_and_create_rbr_request *request = container_of( + callback, + struct xenidc_reserve_and_create_rbr_request, + reserved_callback); + struct xenidc_create_rbr_request_element *element; + trace(); + list_for_each_entry(element, &request->request_elements, link) { + if (element->handle != NULL) { + struct xenidc_lbr_concrete_class **handle = + element->handle; + element->handle = NULL; + xenidc_lbr_revoke_rbr(handle, callback); + return; + } + } + xenidc_rbr_provider_pool_kick_requests(request->pool); + xenidc_callback_serialiser_complete_callback(&callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_revoke_callback + (request), XENIDC_ERROR_SUCCESS); +} + +EXPORT_SYMBOL(xenidc_allocate_rbr_provider_pool); +EXPORT_SYMBOL(xenidc_free_rbr_provider_pool); +EXPORT_SYMBOL(xenidc_rbr_provider_pool_reserve_and_create_rbrs); +EXPORT_SYMBOL(xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs); +EXPORT_SYMBOL(xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs); diff -r 60996909c1c7 -r 0331fa2f86c1 linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h --- /dev/null Fri Nov 25 16:10:28 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h Fri Nov 25 17:36:38 2005 @@ -0,0 +1,244 @@ +/*****************************************************************************/ +/* Xen inter-domain communication remote buffer reference provider pool. */ +/* This component provides a service used by clients to create remote buffer */ +/* references for buffers in the local address space. The remote buffer */ +/* references can be sent in messages or transactions to other domains where */ +/* they can be used to access the buffers. */ +/* */ +/* 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_RBR_PROVIDER_POOL +#define XENIDC_RBR_PROVIDER_POOL + +#include "xenidc_buffer_resource_provider.h" +#include "xenidc_local_buffer_reference.h" +#include "xenidc_remote_buffer_reference.h" + +/* The client uses a xenidc_rbr_provider_pool to create remote buffer */ +/* references for inter-domain bulk data transfer. */ + +struct xenidc_rbr_provider_pool; + +/* The client calls xenidc_allocate_rbr_provider_pool to allocate a pool and */ +/* the resources required to use it. */ +/* xenidc_allocate_rbr_provider_pool returns NULL if the pool cannot be */ +/* allocated or the anti-deadlock allocation fails. */ + +struct xenidc_rbr_provider_pool * +xenidc_allocate_rbr_provider_pool( +struct xenidc_buffer_resource_list anti_deadlock_resource_allocation); + +/* The client calls xenidc_free_rbr_provider_pool to free the pool and all */ +/* its resources. The client must quiesce all use of the pool before */ +/* freeing it. */ + +void +xenidc_free_rbr_provider_pool(struct xenidc_rbr_provider_pool *pool); + +/* Remote buffer references can be created wirh different classes of allowed */ +/* access for the remote domain. These flags indicate what kind of access */ +/* is allowed. */ + +#define XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ \ + XENIDC_LBR_ACCESS_FLAGS_READ +#define XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE \ + XENIDC_LBR_ACCESS_FLAGS_WRITE + +/* The client may create multiple remote buffer references with a single */ +/* request. This is required for the resource management strategy described */ +/* in the xenidc.h file. The parameters for each remote buffer reference */ +/* are passed using a xenidc_create_rbr_request_element structure. The */ +/* request has a list of these structures. */ + +struct xenidc_create_rbr_request_element { + struct list_head link; + struct xenidc_lbr lbr; + int access_flags; + struct xenidc_rbr rbr; + struct xenidc_lbr_concrete_class **handle; +}; + +/* The client must initialise the element before first use. */ + +static inline void xenidc_create_rbr_request_element_init( +struct xenidc_create_rbr_request_element *element) +{ + memset(element, 0, sizeof(*element)); + INIT_LIST_HEAD(&element->link); +} + +/* The client must set a local buffer reference to describe the buffer for */ +/* which a remote buffer reference is to be created. */ + +static inline void +xenidc_create_rbr_request_element_set_lbr( +struct xenidc_create_rbr_request_element *element, struct xenidc_lbr lbr, +int access_flags) +{ + element->lbr = lbr; + element->access_flags = access_flags; +} + +/* Once the request completes, the client may use */ +/* xenidc_create_rbr_request_element_query_rbr to get a copy of the remote */ +/* buffer reference created. */ + +static inline struct xenidc_rbr +xenidc_create_rbr_request_element_query_rbr( +struct xenidc_create_rbr_request_element *element) +{ + return element->rbr; +} + +/* Elements are added to the element list on the request and then the */ +/* request is submitted. xenidc_create_rbr_request_element_ensure_removed */ +/* may be used while the element is initialised and idle to ensure that the */ +/* element is removed from the request list. */ + +static inline void +xenidc_create_rbr_request_element_ensure_removed( +struct xenidc_create_rbr_request_element *element) +{ + list_del_init(&element->link); +} + +/* The request structure is used to create a number of remote buffer */ +/* references, one for each element on the list. */ + +struct xenidc_reserve_and_create_rbr_request { + struct xenidc_callback create_callback; + struct xenidc_callback revoke_callback; + struct xenidc_rbr_provider_pool *pool; + struct xenidc_address address; + struct list_head request_elements; + struct xenidc_callback reserved_callback; +}; + +#define XENIDC_RESERVE_AND_CREATE_RBR_REQUEST_LINK \ +create_callback.XENIDC_CALLBACK_LINK + +/* The request structure contains two callbacks, one for when the remote */ +/* buffer references are created and one for when they are later revoked. */ +/* Each callback contains a link which may be used by the current owner of */ +/* the request. */ + +static inline struct xenidc_callback * +xenidc_reserve_and_create_rbr_request_to_create_callback( +struct xenidc_reserve_and_create_rbr_request *request) +{ + return &request->create_callback; +} + +static inline struct xenidc_reserve_and_create_rbr_request * +xenidc_reserve_and_create_rbr_request_create_callback_to( +struct xenidc_callback * callback) +{ + return container_of(callback, + struct xenidc_reserve_and_create_rbr_request, create_callback); +} + +static inline struct xenidc_callback * +xenidc_reserve_and_create_rbr_request_to_revoke_callback( +struct xenidc_reserve_and_create_rbr_request *request) +{ + return &request->revoke_callback; +} + +static inline struct xenidc_reserve_and_create_rbr_request * +xenidc_reserve_and_create_rbr_request_revoke_callback_to( +struct xenidc_callback * callback) +{ + return container_of(callback, + struct xenidc_reserve_and_create_rbr_request, revoke_callback); +} + +static inline struct list_head * +xenidc_reserve_and_create_rbr_request_to_link( +struct xenidc_reserve_and_create_rbr_request *request) +{ + return xenidc_callback_to_link( + xenidc_reserve_and_create_rbr_request_to_create_callback( + request)); +} + +static inline struct xenidc_reserve_and_create_rbr_request * +xenidc_reserve_and_create_rbr_request_link_to(struct list_head *link) +{ + return xenidc_reserve_and_create_rbr_request_create_callback_to( + xenidc_callback_link_to(link)); +} + +/* The request is initialised by the client with create and revoke callback */ +/* functions that are called, respectively, on completion of the create and */ +/* revoke operations. */ + +static inline void +xenidc_reserve_and_create_rbr_request_init( +struct xenidc_reserve_and_create_rbr_request *request, +xenidc_callback_function *create_callback, +xenidc_callback_function *revoke_callback) +{ + xenidc_callback_init(&request->create_callback, create_callback); + xenidc_callback_init(&request->revoke_callback, revoke_callback); + + INIT_LIST_HEAD(&request->request_elements); +} + +/* xenidc_reserve_and_create_rbr_request_add_element is used to add an */ +/* element to the request's list of elements to be created. */ + +static inline void +xenidc_reserve_and_create_rbr_request_add_element( +struct xenidc_reserve_and_create_rbr_request *request, +struct xenidc_create_rbr_request_element *element) +{ + list_add(&element->link, &request->request_elements); +} + +/* The client calls xenidc_rbr_provider_pool_reserve_and_create_rbrs to */ +/* reserve the required resources and then create the remote buffer */ +/* references for the local buffers referenced by local buffer references in */ +/* the elements of the request list. */ + +void +xenidc_rbr_provider_pool_reserve_and_create_rbrs( +struct xenidc_rbr_provider_pool *pool, +struct xenidc_reserve_and_create_rbr_request *request, +struct xenidc_address address); + +/* The client calls xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs */ +/* to abort an outstanding xenidc_rbr_provider_pool_reserve_and_create_rbrs */ +/* operation. After abort call, the request will either complete */ +/* successfully (sucessful completion may have already been scheduled when */ +/* the abort call is made) or will complete with the provided error value */ +/* after having been aborted. */ + +void +xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs( +struct xenidc_reserve_and_create_rbr_request *request, xenidc_error error); + +/* The client calls xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs to */ +/* revoke remote access to the buffers and free and unreserve the resources */ +/* usen when the remote buffer references were created. */ + +void +xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs( +struct xenidc_reserve_and_create_rbr_request *request); + +#endif