Coherent4.2.10/coh.386/lib/ddi_defer.c

Compare this file to the similar file:
Show the results in this format:

/* $Header: $ */

#define	_DDI_DKI	1
#define	_DDI_DKI_IMPL	1
#define	_SYSV4		1

/*
 * $Log: $
 */

/*
 *-IMPORTS:
 *	<common/ccompat.h>
 *		__USE_PROTO__
 *		__ARGS ()
 *	<sys/debug.h>
 *		ASSERT ()
 *	<kernel/ddi_cpu.h>
 *		dcdata_t
 *		ddi_cpu_data ()
 *	<kernel/ddi_glob.h>
 *		dgdata_t
 *		ddi_global_data ()
 *	<kernel/ddi_lock.h>
 *		defer_priority
 *		defer_hierarchy
 *	<sys/ksynch.h>
 *		LOCK ()
 *		UNLOCK ()
 *	<sys/cmn_err.h>
 *		CE_WARN
 *		cmn_err ()
 *	<sys/stdlib.h>
 *		NULL
 */

#include <common/ccompat.h>
#include <kernel/ddi_cpu.h>
#include <kernel/ddi_glob.h>
#include <kernel/ddi_lock.h>
#include <sys/debug.h>
#include <sys/ksynch.h>
#include <sys/cmn_err.h>
#include <sys/types.h>
#include <stddef.h>

#include <kernel/defer.h>


/*
 * This internal function queues a deferred function on a deferred-function
 * queue.
 */

#if	__USE_PROTO__
__LOCAL__ int (DEFER) (defer_t * deferp, __deffuncp_t funcp)
#else
__LOCAL__ int
DEFER __ARGS ((deferp, funcp))
defer_t	      *	deferp;
__deffuncp_t	funcp;
#endif
{
	pl_t		prev_pl;
	int		idx;

	ASSERT (funcp != NULL);
	ASSERT (deferp != NULL);
	ASSERT (deferp->df_tab != NULL);
	ASSERT (ATOMIC_FETCH_UCHAR (deferp->df_max) > 0);

	prev_pl = LOCK (deferp->df_wlock, defer_priority);

	/*
	 * Write the function pointer into the next free slot in the table,
	 * and then move the write pointer to the next entry in the circular
	 * buffer.
	 */

	idx = ATOMIC_FETCH_UCHAR (deferp->df_write);

	deferp->df_tab [idx ++] = funcp;

	if (idx == ATOMIC_FETCH_UCHAR (deferp->df_max))
		idx = 0;

	/*
	 * If the write pointer bumps into the read pointer, then the defer
	 * table is full and we should complain. A possible alternative
	 * strategy would be to wait for the other processor, but that is only
	 * a good idea if we have the machinery to interrupt it available,
	 * which we currently do not.
	 */

	if (idx != ATOMIC_FETCH_UCHAR (deferp->df_read)) {
		/*
		 * Store the updated write pointer and prepare to return
		 * success.
		 */

		ATOMIC_STORE_UCHAR (deferp->df_write, idx);
		idx = 0;
	} else {

		cmn_err (CE_WARN, "table overflow in DEFER ()");
		idx = 1;	/* flag failure to the caller */
	}

	UNLOCK (deferp->df_wlock, prev_pl);

	return idx;
}


/*
 *-STATUS:
 *	For the Implementors only.
 *
 *-NAME:
 *	defer_int_cpu	Defer a routine on a specified CPU.
 *
 *-SYNOPSIS:
 *	#include <kernel/defer.h>
 *
 *	int defer_int_cpu (void (* funcp) (void), processorid_t cpuid);
 *
 *-ARGUMENTS:
 *	funcp		Pointer to the function to be executed upon the given
 *			processor's return from kernel execution to user-level
 *			execution.
 *
 *	cpuid		Processor on which "funcp" is to be executed.
 *
 *-DESCRIPTION:
 *	defer_int_cpu () requests that a function be executed on the given CPU
 *	at a priority higher than any user-level code. If the given CPU is
 *	currently executing kernel code, the function will be run before user-
 *	level execution is resumed. The routine is run at a priority lower
 *	than any interrupt-level code; if the implementation permits, the
 *	routine will be run at a priority higher than base kernel code, but
 *	this is not guaranteed.
 *
 *	The implementation will make a best effort to ensure that the deferred
 *	function is executed promptly. However, some hardware configurations
 *	may not permit one CPU to interrupt another under software control, so
 *	if the specified CPU is currently running at user level it may not
 *	execute the deferred function for some time.
 *
 *-RETURN VALUE:
 *	0 is returned on success. If the specified CPU is invalid, or the
 *	deferred-function table for the specified CPU is full, then a non-zero
 *	error value is returned.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	It is currently unspecified whether the function pointed to by "funcp"
 *	is permitted to contend for locks held by the caller.
 */

#if	__USE_PROTO__
int (defer_int_cpu) (__deffuncp_t funcp, processorid_t cpuid)
#else
int
defer_int_cpu __ARGS ((funcp, cpuid))
__deffuncp_t	funcp;
processorid_t	cpuid;
#endif
{
	dcdata_t      *	dcdatap;
	int		retval;

	ASSERT (funcp != NULL);

	if ((dcdatap = ddi_cpu_ref (cpuid)) == NULL)
		return -1;

	retval = DEFER (& dcdatap->dc_defint, funcp);

	ddi_cpu_unref (dcdatap);
	return retval;
}


/*
 *-STATUS:
 *	For the Implementors only.
 *
 *-NAME:
 *	defer_int_any	Defer a routine on an unspecified CPU.
 *
 *-SYNOPSIS:
 *	#include <kernel/defer.h>
 *
 *	int defer_int_any (void (* funcp) (void));
 *
 *-ARGUMENTS:
 *	funcp		Pointer to the function to be executed upon some
 *			processor's return from kernel execution to user-level
 *			execution.
 *
 *-DESCRIPTION:
 *	defer_int_any () requests that a function be executed at some future
 *	time convenient to the implementation. The routine will be run at a
 *	priority higher than any user-level code, and lower than any
 *	interrupt-level code; if the implementation permits, the function will
 *	be run at a priority higher than base kernel code, but this is not
 *	guaranteed.
 *
 *	The function will be executed on the first CPU available. However, a
 *	typical implementation would not interrupt user-level execution on
 *	any other CPUs merely to run deferred functions.
 *
 *-RETURN VALUE:
 *	0 is returned on success. If the global deferred-function table is
 *	full, then a non-zero error value is returned.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	It is currently unspecified whether the function pointed to by "funcp"
 *	is permitted to contend for locks held by the caller.
 */

#if	__USE_PROTO__
int (defer_int_any) (__deffuncp_t funcp)
#else
int
defer_int_any __ARGS ((funcp))
__deffuncp_t	funcp;
#endif
{
	return DEFER (& ddi_global_data ()->dg_defint, funcp);
}


/*
 *-STATUS:
 *	For the Implementors only.
 *
 *-NAME:
 *	defer_int_here	Defer a routine on the current CPU.
 *
 *-SYNOPSIS:
 *	#include <kernel/defer.h>
 *
 *	int defer_int_here (void (* funcp) (void));
 *
 *-ARGUMENTS:
 *	funcp		Pointer to the function to be executed upon this
 *			processor's return from kernel execution to user-level
 *			execution.
 *
 *-DESCRIPTION:
 *	defer_int_here () requests that a function be executed at some future
 *	time convenient to the implementation on the current CPU. The routine
 *	will be run at a priority higher than any user-level code, and lower
 *	than any interrupt-level code; if the implementation permits, the
 *	function will run at a level higher than base kernel code, but this is
 *	not guaranteed.
 *
 *-RETURN VALUE:
 *	0 is returned on success. If the current CPUs deferred-function table
 *	is full, then a non-zero error value is returned.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	It is currently unspecified whether the function pointed to by "funcp"
 *	is permitted to contend for locks held by the caller.
 */

#if	__USE_PROTO__
int (defer_int_here) (__deffuncp_t funcp)
#else
int
defer_int_here __ARGS ((funcp))
__deffuncp_t	funcp;
#endif
{
	return DEFER (& ddi_cpu_data ()->dc_defint, funcp);
}


/*
 *-STATUS:
 *	For the Implementors only.
 *
 *-NAME:
 *	defer_proc_cpu	Defer a routine on a specified CPU.
 *
 *-SYNOPSIS:
 *	#include <kernel/defer.h>
 *
 *	int defer_proc_cpu (void (* funcp) (void), processorid_t cpuid);
 *
 *-ARGUMENTS:
 *	funcp		Pointer to the function to be executed upon the given
 *			processor's return from kernel execution to user-level
 *			execution.
 *
 *	cpuid		Processor on which "funcp" is to be executed.
 *
 *-DESCRIPTION:
 *	defer_proc_cpu () requests that a function be executed on the given CPU
 *	at a priority higher than any user-level code. If the given CPU is
 *	currently executing kernel code, the function will be run before user-
 *	level execution is resumed.
 *
 *	The implementation will make a best effort to ensure that the deferred
 *	function is executed promptly. However, some hardware configurations
 *	may not permit one CPU to interrupt another under software control, so
 *	if the specified CPU is currently running at user level it may not
 *	execute the deferred function for some time.
 *
 *-RETURN VALUE:
 *	0 is returned on success. If the specified CPU is invalid, or the
 *	deferred-function table for the specified CPU is full, then a non-zero
 *	error value is returned.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	It is currently unspecified whether the function pointed to by "funcp"
 *	is permitted to contend for locks held by the caller.
 */

#if	__USE_PROTO__
int (defer_proc_cpu) (__deffuncp_t funcp, processorid_t cpuid)
#else
int
defer_proc_cpu __ARGS ((funcp, cpuid))
__deffuncp_t	funcp;
processorid_t	cpuid;
#endif
{
	dcdata_t      *	dcdatap;
	int		retval;

	ASSERT (funcp != NULL);

	if ((dcdatap = ddi_cpu_ref (cpuid)) == NULL)
		return -1;

	retval = DEFER (& dcdatap->dc_defproc, funcp);

	ddi_cpu_unref (dcdatap);
	return retval;
}


/*
 *-STATUS:
 *	For the Implementors only.
 *
 *-NAME:
 *	defer_proc_any	Defer a routine on an unspecified CPU.
 *
 *-SYNOPSIS:
 *	#include <kernel/defer.h>
 *
 *	int defer_proc_any (void (* funcp) (void));
 *
 *-ARGUMENTS:
 *	funcp		Pointer to the function to be executed upon some
 *			processor's return from kernel execution to user-level
 *			execution.
 *
 *-DESCRIPTION:
 *	defer_proc_any () requests that a function be executed at some future
 *	time convenient to the implementation. The routine will be run at a
 *	priority higher than any user-level code, and lower than any
 *	interrupt-level code or kernel code.
 *
 *	The function will be executed on the first CPU available. However, a
 *	typical implementation would not interrupt user-level execution on
 *	any other CPUs merely to run deferred functions.
 *
 *-RETURN VALUE:
 *	0 is returned on success. If the global deferred-function table is
 *	full, then a non-zero error value is returned.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	It is currently unspecified whether the function pointed to by "funcp"
 *	is permitted to contend for locks held by the caller.
 */

#if	__USE_PROTO__
int (defer_proc_any) (__deffuncp_t funcp)
#else
int
defer_proc_any __ARGS ((funcp))
__deffuncp_t	funcp;
#endif
{
	return DEFER (& ddi_global_data ()->dg_defproc, funcp);
}


/*
 *-STATUS:
 *	For the Implementors only.
 *
 *-NAME:
 *	defer_proc_here	Defer a routine on the current CPU.
 *
 *-SYNOPSIS:
 *	#include <kernel/defer.h>
 *
 *	int defer_proc_here (void (* funcp) (void));
 *
 *-ARGUMENTS:
 *	funcp		Pointer to the function to be executed upon this
 *			processor's return from kernel execution to user-level
 *			execution.
 *
 *-DESCRIPTION:
 *	defer_proc_here () requests that a function be executed at some future
 *	time convenient to the implementation on the current CPU. The routine
 *	will be run at a priority higher than any user-level code, and lower
 *	than any interrupt-level code or kernel code.
 *
 *-RETURN VALUE:
 *	0 is returned on success. If the current CPUs deferred-function table
 *	is full, then a non-zero error value is returned.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	It is currently unspecified whether the function pointed to by "funcp"
 *	is permitted to contend for locks held by the caller.
 */

#if	__USE_PROTO__
int (defer_proc_here) (__deffuncp_t funcp)
#else
int
defer_proc_here __ARGS ((funcp))
__deffuncp_t	funcp;
#endif
{
	return DEFER (& ddi_cpu_data ()->dc_defproc, funcp);
}