diff -r d4ea70e2848e -r e4a76dd06289 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Mon Nov 21 11:04:23 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Mon Nov 21 11:09:01 2005 @@ -17,3 +17,4 @@ xenidc-objs += xenidc_gateway_target_resource.o xenidc-objs += xenidc_endpoint.o xenidc-objs += xenidc_rbr_provider_pool.o +xenidc-objs += xenidc_rbr_mapper_pool.o diff -r d4ea70e2848e -r e4a76dd06289 linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h --- a/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h Mon Nov 21 11:04:23 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h Mon Nov 21 11:09:01 2005 @@ -57,6 +57,12 @@ XENIDC_LOCAL_BUFFER_REFERENCE_ACCESS_FLAGS_READ #define XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE \ XENIDC_LOCAL_BUFFER_REFERENCE_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. */ /* The client may create multiple remote buffer references with a single */ /* request. This is required for the resource management strategy described */ diff -r d4ea70e2848e -r e4a76dd06289 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c --- /dev/null Mon Nov 21 11:04:23 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c Mon Nov 21 11:09:01 2005 @@ -0,0 +1,370 @@ +/*****************************************************************************/ +/* Xen remote buffer reference mapper 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(xenidc_rbr_mapper_pool_callback_serialiser); + +struct xenidc_rbr_mapper_pool_struct { + xenidc_buffer_resource_list anti_deadlock_resource_allocation; + + xenidc_buffer_resource_provider *provider; + + spinlock_t lock; + + xenidc_buffer_resource_list head_request_required_resources; + + struct list_head request_list; + + int kicking_requests:1; + int head_request_required_resources_calculated:1; +}; + +static int xenidc_rbr_mapper_pool_init_or_exit + (xenidc_rbr_mapper_pool * pool, int exit) { + trace(); + + { + int return_value = 0; + + if (exit) { + goto EXIT; + } + + pool->provider = xenidc_allocate_buffer_resource_provider + (pool->anti_deadlock_resource_allocation); + + 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_required_resources_calculated = 0; + + return 0; + + EXIT: + + xenidc_free_buffer_resource_provider(pool->provider); + + EXIT_NO_PROVIDER: + + return return_value; + } +} + +xenidc_rbr_mapper_pool *xenidc_allocate_rbr_mapper_pool + (xenidc_buffer_resource_list anti_deadlock_resource_allocation) { + trace(); + + { + xenidc_rbr_mapper_pool *pool = (xenidc_rbr_mapper_pool *) + vmalloc(sizeof(xenidc_rbr_mapper_pool)); + + if (pool != NULL) { + pool->anti_deadlock_resource_allocation = + anti_deadlock_resource_allocation; + + if (xenidc_rbr_mapper_pool_init_or_exit(pool, 0) != 0) { + vfree(pool); + + pool = NULL; + } + } + + return pool; + } +} + +void xenidc_free_rbr_mapper_pool(xenidc_rbr_mapper_pool * pool) +{ + trace(); + + (void)xenidc_rbr_mapper_pool_init_or_exit(pool, 1); + + vfree(pool); +} + +static void xenidc_rbr_mapper_pool_kick_requests(xenidc_rbr_mapper_pool * pool); + +void xenidc_rbr_mapper_pool_reserve_and_map_rbrs + (xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request, xenidc_address address) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + request->pool = pool; + request->address = address; + + { + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); + + list_add_tail + (xenidc_reserve_and_map_rbr_request_to_link(request), + &pool->request_list); + + spin_unlock_irqrestore(&pool->lock, flags); + } + + xenidc_rbr_mapper_pool_kick_requests(pool); +} + +static int xenidc_rbr_mapper_pool_calculate_required_resources + (xenidc_reserve_and_map_rbr_request * request, + xenidc_buffer_resource_list * list) { + trace(); + + *list = xenidc_buffer_resource_list_null(); + + { + xenidc_map_rbr_request_element *element; + + list_for_each_entry(element, &request->request_elements, link) { + xenidc_buffer_resource_list element_list; + + if (xenidc_remote_buffer_reference_calculate_map_resources(&element->rbr, &request->address, &element_list) + != 0) { + return 1; + } + + xenidc_buffer_resource_list_plus_equals(list, + &element_list); + } + } + + return 0; +} + +static void xenidc_rbr_mapper_pool_service_request + (xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + int error = 0; + + xenidc_map_rbr_request_element *element; + + list_for_each_entry(element, &request->request_elements, link) { + if (!error) { + element->handle = + xenidc_remote_buffer_reference_map_rbr + (&element->rbr, &request->address, + pool->provider, &element->mapping, + element->access_flags); + + if (element->handle == NULL) { + error = 1; + } + } else { + element->handle = NULL; + } + } + + if (error) { + goto ERROR; + } + } + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_mapper_pool_callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_map_callback(request), + XENIDC_ERROR_SUCCESS); + + return; + + ERROR: + + { + xenidc_map_rbr_request_element *element; + + list_for_each_entry(element, &request->request_elements, link) { + if (element->handle != NULL) { + xenidc_remote_buffer_reference_unmap_rbr + (element->handle); + } + } + } + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_mapper_pool_callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_map_callback(request), + XENIDC_ERROR_INVALID_PARAMETER); +} + +static void xenidc_rbr_mapper_pool_kick_requests(xenidc_rbr_mapper_pool * pool) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); + + while ((!pool->kicking_requests) + && (!list_empty(&pool->request_list)) + ) { + xenidc_reserve_and_map_rbr_request *request = + xenidc_reserve_and_map_rbr_request_link_to + (pool->request_list.next); + + if (!pool->head_request_required_resources_calculated) { + if ((xenidc_rbr_mapper_pool_calculate_required_resources(request, &pool->head_request_required_resources) + != 0) + || + (!xenidc_buffer_resource_list_subset_of + (&pool->head_request_required_resources, + &pool->anti_deadlock_resource_allocation) + ) + ) { + list_del_init + (xenidc_reserve_and_map_rbr_request_to_link + (request) + ); + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_mapper_pool_callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_map_callback + (request), XENIDC_ERROR_TOO_BIG); + + continue; + } + + pool-> + head_request_required_resources_calculated = + 1; + } + + { + xenidc_buffer_resource_list free_resources = + xenidc_buffer_resource_provider_query_free_resources + (pool->provider); + + if (!xenidc_buffer_resource_list_subset_of + (&pool->head_request_required_resources, + &free_resources) + ) { + break; + } + } + + list_del_init + (xenidc_reserve_and_map_rbr_request_to_link + (request)); + + pool->head_request_required_resources_calculated = 0; + + pool->kicking_requests = 1; + + spin_unlock_irqrestore(&pool->lock, flags); + + xenidc_rbr_mapper_pool_service_request(pool, request); + + spin_lock_irqsave(&pool->lock, flags); + + pool->kicking_requests = 0; + } + + spin_unlock_irqrestore(&pool->lock, flags); + } +} + +void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs + (xenidc_reserve_and_map_rbr_request * request, xenidc_error error) { + trace(); + + { + xenidc_rbr_mapper_pool *pool = request->pool; + + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); + + { + xenidc_reserve_and_map_rbr_request *queued_request; + + list_for_each_entry + (queued_request, + &pool->request_list, + XENIDC_RESERVE_AND_MAP_RBR_REQUEST_LINK) { + if (request == queued_request) { + list_del_init + (xenidc_reserve_and_map_rbr_request_to_link + (request) + ); + + pool-> + head_request_required_resources_calculated + = 0; + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_mapper_pool_callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_map_callback + (request), error); + + break; + } + } + } + + spin_unlock_irqrestore(&pool->lock, flags); + } +} + +void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs + (xenidc_reserve_and_map_rbr_request * request) { + trace(); + + { + xenidc_map_rbr_request_element *element; + + list_for_each_entry(element, &request->request_elements, link) { + xenidc_remote_buffer_reference_unmap_rbr(element-> + handle); + } + } + + xenidc_rbr_mapper_pool_kick_requests(request->pool); + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_mapper_pool_callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_unmap_callback(request), + XENIDC_ERROR_SUCCESS); +} + +EXPORT_SYMBOL(xenidc_allocate_rbr_mapper_pool); +EXPORT_SYMBOL(xenidc_free_rbr_mapper_pool); +EXPORT_SYMBOL(xenidc_rbr_mapper_pool_reserve_and_map_rbrs); +EXPORT_SYMBOL(xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs); +EXPORT_SYMBOL(xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs); diff -r d4ea70e2848e -r e4a76dd06289 linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h --- /dev/null Mon Nov 21 11:04:23 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h Mon Nov 21 11:09:01 2005 @@ -0,0 +1,213 @@ +/*****************************************************************************/ +/* Xen inter-domain communication remote buffer reference mapper pool. This */ +/* provides a service used by clients to map buffers referenced by remote */ +/* buffer references into the local address space. */ +/* */ +/* 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 __ASM_XEN_XENIDC_RBR_MAPPER_POOL_H__ +#define __ASM_XEN_XENIDC_RBR_MAPPER_POOL_H__ + +#include "xenidc_callback.h" +#include "xenidc_remote_buffer_reference.h" + +/* The client uses a xenidc_rbr_mapper_pool to map buffers referenced by */ +/* remote buffer references into the local address space. */ + +typedef struct xenidc_rbr_mapper_pool_struct xenidc_rbr_mapper_pool; + +/* The client uses xenidc_allocate_rbr_mapper_pool to allocate a */ +/* xenidc_rbr_mapper_pool and its minimum resource allocation. This function */ +/* returns NULL if the pool cannot be allocated or the anti-deadlock */ +/* allocation fails. */ + +extern xenidc_rbr_mapper_pool *xenidc_allocate_rbr_mapper_pool + (xenidc_buffer_resource_list anti_deadlock_resource_allocation); + +/* The client calls xenidc_free_rbr_mapper_pool to free the pool and the */ +/* pools resource allocation. The client must quiesce all use of the pool */ +/* before attempting to free it. */ + +extern void xenidc_free_rbr_mapper_pool(xenidc_rbr_mapper_pool * pool); + +/* The client may request read or write or read write access to buffers when */ +/* mapping them. The requested access must be a subset of the access */ +/* granted by the owner of the buffer for mapping to be sucessful. */ + +#define XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ \ +XENIDC_REMOTE_BUFFER_REFERENCE_ACCESS_FLAGS_READ +#define XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE \ +XENIDC_REMOTE_BUFFER_REFERENCE_ACCESS_FLAGS_WRITE + +/* Requests to map buffers consist of a list of elements, one for each */ +/* buffer to be mapped. This is necessary for the resource management */ +/* strategy described in the xenidc.h header file. */ + +typedef struct xenidc_map_rbr_request_element_struct + xenidc_map_rbr_request_element; + +/* The client is responsible for allocating the request elements. */ + +struct xenidc_map_rbr_request_element_struct { + struct list_head link; + xenidc_remote_buffer_reference rbr; + int access_flags; + void *mapping; + xenidc_buffer_mappable_class **handle; +}; + +/* The client must initialise the request element before first use. */ + +static inline void xenidc_map_rbr_request_element_init + (xenidc_map_rbr_request_element * element) { + memset(element, 0, sizeof(*element)); + + INIT_LIST_HEAD(&element->link); +} + +/* The client sets a remote buffer reference in the element. This */ +/* references a buffer to be mapped when the request is submitted. */ + +static inline void xenidc_map_rbr_request_element_set_rbr + (xenidc_map_rbr_request_element * element, + xenidc_remote_buffer_reference rbr, int access_flags) { + element->rbr = rbr; + element->access_flags = access_flags; +} + +/* Request elements are added to a list in the request. */ +/* xenidc_map_rbr_request_element_ensure_removed may be called after the */ +/* element is initialised to ensure that the element is no longer present on */ +/* a request list. */ + +static inline void xenidc_map_rbr_request_element_ensure_removed + (xenidc_map_rbr_request_element * element) { + list_del_init(&element->link); +} + +/* The client is responsible for allocating the request. */ + +typedef struct xenidc_reserve_and_map_rbr_request_struct + xenidc_reserve_and_map_rbr_request; + +struct xenidc_reserve_and_map_rbr_request_struct { + xenidc_callback map_callback; + xenidc_callback unmap_callback; + xenidc_rbr_mapper_pool *pool; + xenidc_address address; + struct list_head request_elements; +}; + +/* The request contains two callbacks, the map callback is for the */ +/* completion of the map operation; the unmap callback is for the completion */ +/* of the unmap operation. The callbacks contain links which are for use by */ +/* the current owner of the request. */ + +#define XENIDC_RESERVE_AND_MAP_RBR_REQUEST_LINK \ +map_callback.XENIDC_CALLBACK_LINK + +static inline xenidc_callback + *xenidc_reserve_and_map_rbr_request_to_map_callback + (xenidc_reserve_and_map_rbr_request * request) { + return &request->map_callback; +} + +static inline xenidc_reserve_and_map_rbr_request + *xenidc_reserve_and_map_rbr_request_map_callback_to(xenidc_callback * + callback) { + return container_of(callback, xenidc_reserve_and_map_rbr_request, + map_callback); +} + +static inline xenidc_callback + *xenidc_reserve_and_map_rbr_request_to_unmap_callback + (xenidc_reserve_and_map_rbr_request * request) { + return &request->unmap_callback; +} + +static inline xenidc_reserve_and_map_rbr_request + *xenidc_reserve_and_map_rbr_request_unmap_callback_to(xenidc_callback * + callback) { + return container_of(callback, xenidc_reserve_and_map_rbr_request, + unmap_callback); +} + +static inline struct list_head *xenidc_reserve_and_map_rbr_request_to_link + (xenidc_reserve_and_map_rbr_request * request) { + return xenidc_callback_to_link + (xenidc_reserve_and_map_rbr_request_to_map_callback(request)); +} + +static inline xenidc_reserve_and_map_rbr_request + *xenidc_reserve_and_map_rbr_request_link_to(struct list_head *link) +{ + return xenidc_reserve_and_map_rbr_request_map_callback_to + (xenidc_callback_link_to(link)); +} + +/* The client initialises the request with callback functions for the map */ +/* and unmap callbacks. */ + +static inline void xenidc_reserve_and_map_rbr_request_init + (xenidc_reserve_and_map_rbr_request * request, + xenidc_callback_function * map_callback, + xenidc_callback_function * unmap_callback) { + xenidc_callback_init(&request->map_callback, map_callback); + xenidc_callback_init(&request->unmap_callback, unmap_callback); + + INIT_LIST_HEAD(&request->request_elements); +} + +/* The client adds elements to the request before submitting it and may only */ +/* remove elements after completion of the unmap callback or a sucessful */ +/* abort. */ + +static inline void xenidc_reserve_and_map_rbr_request_add_element + (xenidc_reserve_and_map_rbr_request * request, + xenidc_map_rbr_request_element * element) { + list_add(&element->link, &request->request_elements); +} + +/* The client calls xenidc_rbr_mapper_pool_reserve_and_map_rbrs to reserve */ +/* the resources and map the remote buffer references of the element list. */ +/* The map callback is completed when the mapping has been performed or if */ +/* it fails. Check the map callback's error value to see if the mapping was */ +/* successful. */ + +extern void xenidc_rbr_mapper_pool_reserve_and_map_rbrs + (xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request, xenidc_address address); + +/* The client calls xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs to */ +/* abort an outstanding map request. After abort call, the request will */ +/* either complete successfully (completion may have already been scheduled) */ +/* or will complete with the provided error value after having been aborted. */ + +extern void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs + (xenidc_reserve_and_map_rbr_request * request, xenidc_error error); + +/* The client calls xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs to unmap */ +/* the buffers and free and unreserve the resources used by the map call. */ +/* The client should only call thsi function when the map operation was */ +/* successful; not if it failed or was successfully aborted. */ + +extern void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs + (xenidc_reserve_and_map_rbr_request * request); + +#endif