Subject: SMP API things, take 2
To: None <tech-smp@netbsd.org>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: tech-smp
Date: 07/29/1999 13:08:22
The following is an update to my previous message.  Note that some of
these things have already been committed to NetBSD-current.

The major change here is the auto-spl simplelock support (which I have
working on the i386, and the changes for all the other ports are coming
along...)

        -- Jason R. Thorpe <thorpej@nas.nasa.gov>

The following is to propose some basic API components necessary
for multiprocessor support in the NetBSD kernel.

IMPORTANT NOTE
--------------

Some people have suggested that a data type `cpuid_t' be introduced to
hold CPU identifiers.  After some consideration, I have concluded that
the type `unsigned long' is preferable for the following reasons:

	Machine-independent code may wish to print out the value of
	a CPU identifier.  Therefore a type with a well-defined printf
	format should be used.

	The `unsigned long' type is the size of a register on all current
	ILP32 and LP64 platforms supported by NetBSD.  Therefore, this
	type is safe to use for this purpose on all platforms.



HEADER FILES
------------

API components will be defined in <machine/cpu.h> and by <machine/lock.h>.
The <machine/lock.h> header will be included by <sys/lock.h> only if the
CPP symbol MULTIPROCESSOR is defined.


FUNCTIONS AND MACROS
--------------------

The following functions or macros will be exported by <machine/cpu.h>:

	u_long cpu_number(void);

		MANDATORY

		This function, inline function, or macro returns the
		CPU identifier of the currently-running CPU.  If the
		system does not support multiple processors, or the
		kernel is built without support for multiple processors,
		this value should return a constant, unspecified value.

	struct cpu_info *curcpu(void);

		only if MULTIPROCESSOR

		This function, inline function, or macro returns the
		CPU identifier of the currently-running CPU.  See below
		for information about the cpu_info structure.

	int cpu_lock_spl(int);

		MANDATORY

		This function, inline function, or macro performs
		the appropriate spl*() operation according to
		the provided LK_SPL_* token (see below).  Its return
		value will be passed to splx().

		XXX Should be in <machine/intr.h>.


The following macros will be exported by <machine/cpu.h>:

	LK_SPL_NONE

		MANDATORY

		This macro is an integer constant representing that
		no raising of interrupt priority is necessary when
		asserting the lock.

	The following are mandatory integer constants representing
	that interrupt priority should be raised to the specified
	level when asserting the lock:

		LK_SPL_SOFTNET		splsoftnet()
		LK_SPL_BIO		splbio()
		LK_SPL_NET		splnet()
		LK_SPL_TTY		spltty()
		LK_SPL_IMP		splimp()
		LK_SPL_CLOCK		splclock()
		LK_SPL_STATCLOCK	splstatclock()
		LK_SPL_HIGH		splhigh()

	The following are mandatory if the associated spl*() function
	is defined for the platform:

		LK_SPL_AUDIO		splaudio()
		LK_SPL_SERIAL		splserial()
		LK_SPL_SOFTSERIAL	splsoftserial()

		XXX Should be in <machine/intr.h>


The following macros may be exported by <machine/lock.h>:

	SIMPLELOCK_LOCKED

		OPTIONAL

		This macro is an integer constant representing the
		value the `lock_data' member of `struct simplelock'
		will hold while the simple lock is locked.  If
		this is not defined, <sys/lock.h> will define it
		to the value 1.

	SIMPLELOCK_UNLOCKED

		OPTIONAL

		This macro is an integer constant representing the
		value the `lock_data' member of `struct simplelock'
		will hold while the simple lock is unlocked.  If
		this is not defined, <sys/lock.h> will define it
		to the value 0.


The following functions or macros will be exported by <machine/lock.h>:

	void cpu_simple_lock_init(__volatile struct simplelock *alp);

		MANDATORY

		This function, inline function, or macro initializes
		the `lock_data' member of `struct simplelock' to the
		value SIMPLELOCK_UNLOCKED.

	void cpu_simple_lock(__volatile struct simplelock *alp);

		MANDATORY

		This function, inline function, or macro acquires
		the specified simple lock by performing the following
		operations in an atomic manner:

			while (alp->lock_data != SIMPLELOCK_UNLOCKED)
				/* spin */;
			alp->lock_data = SIMPLELOCK_LOCKED;

	int cpu_simple_lock_try(__volatile struct simplelock *alp);

		MANDATORY

		This function, inline function, or macro attempts to
		acquire the specified simple lock by performing the
		following operations in an atomic manner:

			if (alp->lock_data != SIMPLELOCK_UNLOCKED)
				return (0);
			else {
				alp->lock_data = SIMPLELOCK_LOCKED;
				return (1);
			}

	void cpu_simple_unlock(__volatile struct simplelock *alp);

		MANDATORY

		This function, inline function, or macro releases
		a previously acquired simple lock by performing
		the following operation:

			alp->lock_data = SIMPLELOCK_UNLOCKED;


DATA STRUCTURES
---------------

The following data structures will be exported by <machine/cpu.h>:

	struct cpu_info;

		only if MULTIPROCESSOR

		This structure will always export the following members:

		- struct proc *ci_curproc: current process on this processor

		- struct simplelock ci_slock: simple lock for cpu_info
		  structure.  Note that use of this lock must remain
		  untracked in the case of lock debugging.  While this
		  lock is held, all interrupts MUST be blocked, as this
		  lock may be asserted from an interrupt context.

		- u_long ci_cpuid: CPU identifier of associated CPU

		This structure will export the following members if
		the DIAGNOSTIC or LOCKDEBUG CPP symbols are defined:

		- u_long ci_spin_locks: number of spin locks held
		  by this processor

		- u_long ci_simple_locks: number of simple locks held
		  by this processor

		The cpu_info structure will be referenced in <sys/proc.h>
		by the following code block:

#if defined(MULTIPROCESSOR)
#define	curproc		curcpu()->ci_curproc
#else
extern struct proc	*curproc;
#endif