Coherent4.2.10/include/kernel/ddi_cpu.h

/* (-lgl
 *	Coherent 386 release 4.2
 *	Copyright (c) 1982, 1993 by Mark Williams Company.
 *	All rights reserved. May not be copied without permission.
 *	For copying permission and licensing info, write licensing@mwc.com
 -lgl) */

#ifndef	__KERNEL_DDI_CPU_H__
#define	__KERNEL_DDI_CPU_H__

/*
 * This internal header file defines structures and an access procedure for
 * DDI/DKI data that is global per CPU. In a multiprocessor system, each
 * CPU would have a data region that was separate from all others.
 */

#include <common/ccompat.h>
#include <common/__size.h>
#include <common/_intmask.h>
#include <kernel/_cpuid.h>
#include <kernel/_lock.h>
#include <kernel/ddi_data.h>
#include <sys/debug.h>

/*
 * Many DDI/DKI routines specify constraints on the circumstances in which
 * they may be called, for example.
 *	Base level only, eg SV_WAIT ().
 *	Pass interrupt priority level greater than the current level,
 *		eg LOCK ().
 *	Not called from within a streams service routine, eg putbq () with
 *		a high-priority STREAMS message.
 *
 * These assertions are important for maintaining system integrity, but it can
 * be difficult to detect when these constraints a violated under normal
 * circumstances, especially when the probability of failure is expected to
 * be low. Therefore, it is important for routines which specify such
 * constraints to be able to umambiguously detect constraint violations with
 * the highest level of probability possible.
 *
 * However, the testability of these assertions depends on cooperation from
 * a wide range of kernel facilities. In a highly multithreaded system with
 * either multiple processors or the ability to suspend interrupt contexts,
 * or both, it is necessary to be able to make detailed inquiries about the
 * system state to re-establish some of the certainty about system state that
 * is lost in the move to gain extra concurrency.
 */

/*
 * Returns true if we are at base level or if the system cannot distinguish
 * between base and interrupt level; if the system is definitely not at base
 * level, returns false.
 */

#define	IS_BASE_LEVEL()		(ddi_cpu_data ()->dc_int_level == 0)

/*
 * Return true if we are at interrupt level or if the system cannot
 * distinguish between base and interrupt level; if the system is definitely
 * at base level, return false.
 */

#define	IS_INTERRUPT_LEVEL()	(ddi_cpu_data ()->dc_int_level != 0)

/*
 * Enter/exit an interrupt context, maintaining the state variables checked
 * for above.
 */

#define	__DDI_DKI_ENTER_INTERRUPT() \
		((void) (ddi_cpu_data ()->dc_int_level ++))
#define	__DDI_DKI_LEAVE_INTERRUPT() \
		((void) (ddi_cpu_data ()->dc_int_level --))


/*
 * Most of the time we want to include the above in simple assertions.
 */

#define	ASSERT_BASE_LEVEL()	ASSERT (IS_BASE_LEVEL ())


/*
 * Here is a description of the per-CPU data we wish to record.
 *
 * To deal with lock-hierarchy assertions, we use a table of
 * counters instead of maintaining a list of held locks. We do this because
 * (1) the nature of shared read/write locks permits even a single CPU to hold
 * the same lock multiple times, and (2) although TRYLOCK () and UNLOCK ()
 * allow out-of-order acquisition and release we want LOCK () to check
 * rigidly the hierarchy assertions.  The array of counters is mostly O(1), a
 * desirable property.
 *
 * Although a trace of held locks is not unreasonable, it is difficult to set a
 * fixed upper bound on the number of simultaneous locks. Even if we use a
 * counter for multiple acquisitions of shared locks, we can potentially need
 * as many trace records as allocated locks.
 */

typedef struct ddi_cpu_data	dcdata_t;

struct ddi_cpu_data {
	/*
	 * Interrupt-related data are at the front of this structure for easy
	 * access by hand-coded assembly-language support routines.  Same for
	 * the defer-table stuff.
	 */

	processorid_t	dc_cpuid;		/* who are we for? */

	intmask_t	dc_base_mask;		/* interrupt masks */

	unsigned char	dc_int_level;		/* processing interrupts */

	/* Deprecated.  Do not trust this value. */
	unsigned char	dc_user_level;		/* user level/kernel level */

	unsigned char	dc_ipl;			/* current ipl */
	atomic_uchar_t	dc_run_timeouts;	/* run deferred timeouts */


	defer_t		dc_defint;		/* interrupt-deferred ops */
	defer_t		dc_defproc;		/* process-deferred ops */

	unsigned long	dc_reserved_1 [4];	/* RESERVED */

	__lkhier_t	dc_max_hierarchy;	/*
						 * For basic-lock hierarchy
						 * assertions
						 */
	__lkhier_t    *	dc_hierarchy_cnt;

	struct pollwait	*
			dc_pollwait;		/* task performing a poll */

	char	      *	dc_dynalloc;		/* for getting per-cpu data */
	char	      *	dc_dynend;		/* end of free per-cpu data */

	unsigned long	dc_idle_ticks;		/* idle ticks */
	unsigned long	dc_idle_time;		/* reserved */
	unsigned char	dc_is_idle;		/* non-zero if system idle */

	unsigned char	dc_reserved_2 [3];	/* RESERVED */
	unsigned long	dc_reserved_3 [4];	/* RESERVED */
};


__EXTERN_C_BEGIN__

dcdata_t      *	ddi_cpu_data	__PROTO ((void));

#if	_DDI_DKI_IMPL
	/*
	 * Functions for the implementation only.
	 */
__VOID__      * ddi_cpu_alloc	__PROTO ((__size_t _size));
dcdata_t      *	ddi_cpu_ref	__PROTO ((processorid_t _cpu));
void		ddi_cpu_unref	__PROTO ((dcdata_t * _data));
processorid_t	ddi_cpu_id	__PROTO ((void));

#endif

__EXTERN_C_END__


extern	dcdata_t	__ddi_cpu_data [];
extern	char		__ddi_cpu_dynarea [512];

#define	ddi_cpu_data()		(__ddi_cpu_data)

#define	_USE_IDLE_PROCESS	1

#define	__IS_CPU_IDLE()		(ddi_cpu_data ()->dc_is_idle)
#define	__MARK_CPU_IDLE()	((void) (ddi_cpu_data ()->dc_is_idle = 1))
#define	__CLEAR_CPU_IDLE()	((void) (ddi_cpu_data ()->dc_is_idle = 0))

#endif	/* ! defined (__KERNEL_DDI_CPU_H__) */