blob: 1346edae04ccf4cd1c356e4dadd9b518085ea571 [file] [log] [blame]
/*
*
* (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef _KDS_H_
#define _KDS_H_
#include <linux/list.h>
#include <linux/workqueue.h>
#define KDS_WAIT_BLOCKING (ULONG_MAX)
struct kds_resource_set;
typedef void (*kds_callback_fn) (void *callback_parameter, void *callback_extra_parameter);
struct kds_callback
{
kds_callback_fn user_cb; /* real cb */
int direct; /* do direct or queued call? */
struct workqueue_struct *wq;
};
struct kds_link
{
struct kds_resource_set *parent;
struct list_head link;
unsigned long state;
};
struct kds_resource
{
struct kds_link waiters;
};
/* callback API */
/* Initialize a callback object.
*
* Typically created per context or per hw resource.
*
* Callbacks can be performed directly if no nested locking can
* happen in the client.
*
* Nested locking can occur when a lock is held during the kds_async_waitall or
* kds_resource_set_release call. If the callback needs to take the same lock
* nested locking will happen.
*
* If nested locking could happen non-direct callbacks can be requested.
* Callbacks will then be called asynchronous to the triggering call.
*/
int kds_callback_init(struct kds_callback *cb, int direct, kds_callback_fn user_cb);
/* Terminate the use of a callback object.
*
* If the callback object was set up as non-direct
* any pending callbacks will be flushed first.
* Note that to avoid a deadlock the lock callbacks needs
* can't be held when a callback object is terminated.
*/
void kds_callback_term(struct kds_callback *cb);
/* resource object API */
/* initialize a resource handle for a shared resource */
void kds_resource_init(struct kds_resource * const resource);
/*
* Will return 0 on success.
* If the resource is being used or waited -EBUSY is returned.
* The caller should NOT try to terminate a resource that could still have clients.
* After the function returns the resource is no longer known by kds.
*/
int kds_resource_term(struct kds_resource *resource);
/* Asynchronous wait for a set of resources.
* Callback will be called when all resources are available.
* If all the resources was available the callback will be called before kds_async_waitall returns.
* So one must not hold any locks the callback code-flow can take when calling kds_async_waitall.
* Caller considered to own/use the resources until \a kds_rset_release is called.
* exclusive_access_bitmap is a bitmap where a high bit means exclusive access while a low bit means shared access.
* Use the Linux __set_bit API, where the index of the buffer to control is used as the bit index.
*
* Standard Linux error return value.
*/
int kds_async_waitall(
struct kds_resource_set ** const pprset,
struct kds_callback *cb,
void *callback_parameter,
void *callback_extra_parameter,
int number_resources,
unsigned long *exclusive_access_bitmap,
struct kds_resource **resource_list);
/* Synchronous wait for a set of resources.
* Function will return when one of these have happened:
* - all resources have been obtained
* - timeout lapsed while waiting
* - a signal was received while waiting
*
* To wait without a timeout, specify KDS_WAIT_BLOCKING for \a jifies_timeout, otherwise
* the timeout in jiffies. A zero timeout attempts to obtain all resources and returns
* immediately with a timeout if all resources could not be obtained.
*
* Caller considered to own/use the resources when the function returns.
* Caller must release the resources using \a kds_rset_release.
*
* Calling this function while holding already locked resources or other locking primitives is dangerous.
* One must if this is needed decide on a lock order of the resources and/or the other locking primitives
* and always take the resources/locking primitives in the specific order.
*
* Use the ERR_PTR framework to decode the return value.
* NULL = time out
* If IS_ERR then PTR_ERR gives:
* ERESTARTSYS = signal received, retry call after signal
* all other values = internal error, lock failed
* Other values = successful wait, now the owner, must call kds_resource_set_release
*/
struct kds_resource_set *kds_waitall(
int number_resources,
unsigned long *exclusive_access_bitmap,
struct kds_resource **resource_list,
unsigned long jifies_timeout);
/* Release resources after use.
* Caller must handle that other async callbacks will trigger,
* so must avoid holding any locks a callback will take.
*
* The function takes a pointer to your poiner to handle a race
* between a cancelation and a completion.
*
* If the caller can't guarantee that a race can't occur then
* the passed in pointer must be the same in both call paths
* to allow kds to manage the potential race.
*/
void kds_resource_set_release(struct kds_resource_set **pprset);
/* Release resources after use and wait callbacks to complete.
* Caller must handle that other async callbacks will trigger,
* so must avoid holding any locks a callback will take.
*
* The function takes a pointer to your poiner to handle a race
* between a cancelation and a completion.
*
* If the caller can't guarantee that a race can't occur then
* the passed in pointer must be the same in both call paths
* to allow kds to manage the potential race.
*
* This should be used to cancel waits which are pending on a kds
* resource.
*
* It is a bug to call this from atomic contexts and from within
* a kds callback that now owns the kds_rseource.
*/
void kds_resource_set_release_sync(struct kds_resource_set **pprset);
#endif /* _KDS_H_ */