diff -r 0331fa2f86c1 -r 1af0183813dd linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Fri Nov 25 17:36:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Fri Nov 25 18:44:13 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 0331fa2f86c1 -r 1af0183813dd linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c --- /dev/null Fri Nov 25 17:36:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c Fri Nov 25 18:44:13 2005 @@ -0,0 +1,259 @@ +/*****************************************************************************/ +/* 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 "xenidc_trace.h" + +static XENIDC_CALLBACK_SERIALISER(callback_serialiser); + +struct xenidc_rbr_mapper_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_mapper_pool_init_or_exit(struct xenidc_rbr_mapper_pool *pool, +int exit) +{ + int return_value = 0; + trace(); + if (exit) + goto exit; + 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: + xenidc_free_buffer_resource_provider(pool->provider); + exit_no_provider: + return return_value; +} + +struct xenidc_rbr_mapper_pool * +xenidc_allocate_rbr_mapper_pool( +struct xenidc_buffer_resource_list dedicated_resources) +{ + struct xenidc_rbr_mapper_pool *pool; + trace(); + pool = (struct xenidc_rbr_mapper_pool *)kmalloc(sizeof( + struct xenidc_rbr_mapper_pool),GFP_KERNEL); + if (pool != NULL) { + pool->dedicated_resources = + dedicated_resources; + if (xenidc_rbr_mapper_pool_init_or_exit(pool, 0) != 0) { + kfree(pool); + pool = NULL; + } + } + return pool; +} + +void xenidc_free_rbr_mapper_pool(struct xenidc_rbr_mapper_pool *pool) +{ + trace(); + (void)xenidc_rbr_mapper_pool_init_or_exit(pool, 1); + kfree(pool); +} + +static void +xenidc_rbr_mapper_pool_kick_requests(struct xenidc_rbr_mapper_pool *pool); + +void +xenidc_rbr_mapper_pool_reserve_and_map_rbrs( +struct xenidc_rbr_mapper_pool *pool, +struct xenidc_reserve_and_map_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_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_calc_req( +struct xenidc_reserve_and_map_rbr_request *request, +struct xenidc_buffer_resource_list *list) +{ + struct xenidc_map_rbr_request_element *element; + trace(); + *list = xenidc_buffer_resource_list_null(); + list_for_each_entry(element, &request->request_elements, link) { + struct xenidc_buffer_resource_list element_list; + if (xenidc_rbr_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( +struct xenidc_rbr_mapper_pool *pool, +struct xenidc_reserve_and_map_rbr_request *request) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + int error = 0; + struct xenidc_map_rbr_request_element *element; + trace(); + list_for_each_entry(element, &request->request_elements, link) { + if (!error) { + element->handle = xenidc_rbr_map(&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_path; + xenidc_callback_serialiser_complete_callback(&callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_map_callback(request), + XENIDC_ERROR_SUCCESS); + return; + error_path: + list_for_each_entry(element, &request->request_elements, link) { + if (element->handle != NULL) + xenidc_rbr_unmap(element->handle); + } + xenidc_callback_serialiser_complete_callback(&callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_map_callback(request), + XENIDC_ERROR_INVALID_PARAMETER); +} + +static void xenidc_rbr_mapper_pool_kick_requests( +struct xenidc_rbr_mapper_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_reserve_and_map_rbr_request *request = + xenidc_reserve_and_map_rbr_request_link_to( + pool->request_list.next); + struct xenidc_buffer_resource_list free_resources; + if (!pool->head_request_req_calculated) { + if ((xenidc_rbr_mapper_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_map_rbr_request_to_link( + request)); + xenidc_callback_serialiser_complete_callback( + &callback_serialiser, + xenidc_reserve_and_map_rbr_request_to_map_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)) + break; + list_del_init(xenidc_reserve_and_map_rbr_request_to_link( + request)); + pool->head_request_req_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( +struct xenidc_reserve_and_map_rbr_request *request, xenidc_error error) +{ + struct xenidc_rbr_mapper_pool *pool = request->pool; + struct xenidc_reserve_and_map_rbr_request *queued_request; + unsigned long flags; + trace(); + spin_lock_irqsave(&pool->lock, flags); + 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_req_calculated = 0; + xenidc_callback_serialiser_complete_callback( + &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( +struct xenidc_reserve_and_map_rbr_request *request) +{ + struct xenidc_map_rbr_request_element *element; + trace(); + list_for_each_entry(element, &request->request_elements, link) { + xenidc_rbr_unmap(element->handle); + } + xenidc_rbr_mapper_pool_kick_requests(request->pool); + xenidc_callback_serialiser_complete_callback(&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 0331fa2f86c1 -r 1af0183813dd linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h --- /dev/null Fri Nov 25 17:36:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h Fri Nov 25 18:44:13 2005 @@ -0,0 +1,219 @@ +/*****************************************************************************/ +/* 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 XENIDC_RBR_MAPPER_POOL_H +#define 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. */ + +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. */ + +struct xenidc_rbr_mapper_pool * +xenidc_allocate_rbr_mapper_pool( +struct 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. */ + +void xenidc_free_rbr_mapper_pool(struct 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_RBR_ACCESS_FLAGS_READ +#define XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE \ +XENIDC_RBR_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. */ +/* The client is responsible for allocating the request elements. */ + +struct xenidc_map_rbr_request_element { + struct list_head link; + struct xenidc_rbr rbr; + int access_flags; + void *mapping; + struct xenidc_rbr_mappable_class **handle; +}; + +/* The client must initialise the request element before first use. */ + +static inline void +xenidc_map_rbr_request_element_init( +struct 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( +struct xenidc_map_rbr_request_element *element, struct xenidc_rbr 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 while the */ +/* element is idle after it 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( +struct xenidc_map_rbr_request_element *element) +{ + list_del_init(&element->link); +} + +/* The client is responsible for allocating the request. */ + +struct xenidc_reserve_and_map_rbr_request { + struct xenidc_callback map_callback; + struct xenidc_callback unmap_callback; + struct xenidc_rbr_mapper_pool *pool; + struct 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 struct xenidc_callback * +xenidc_reserve_and_map_rbr_request_to_map_callback( +struct xenidc_reserve_and_map_rbr_request *request) +{ + return &request->map_callback; +} + +static inline struct xenidc_reserve_and_map_rbr_request * +xenidc_reserve_and_map_rbr_request_map_callback_to( +struct xenidc_callback *callback) +{ + return container_of(callback, + struct xenidc_reserve_and_map_rbr_request, map_callback); +} + +static inline struct xenidc_callback * +xenidc_reserve_and_map_rbr_request_to_unmap_callback( +struct xenidc_reserve_and_map_rbr_request *request) +{ + return &request->unmap_callback; +} + +static inline struct xenidc_reserve_and_map_rbr_request * +xenidc_reserve_and_map_rbr_request_unmap_callback_to( +struct xenidc_callback *callback) +{ + return container_of(callback, + struct xenidc_reserve_and_map_rbr_request, unmap_callback); +} + +static inline struct list_head * +xenidc_reserve_and_map_rbr_request_to_link( +struct xenidc_reserve_and_map_rbr_request *request) +{ + return xenidc_callback_to_link( + xenidc_reserve_and_map_rbr_request_to_map_callback(request)); +} + +static inline struct 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( +struct 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( +struct xenidc_reserve_and_map_rbr_request *request, +struct 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. */ + +void xenidc_rbr_mapper_pool_reserve_and_map_rbrs( +struct xenidc_rbr_mapper_pool *pool, +struct xenidc_reserve_and_map_rbr_request *request, +struct 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. */ + +void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs( +struct 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. */ + +void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs( +struct xenidc_reserve_and_map_rbr_request *request); + +#endif