/*
 * @(#)alpha.gcc	10.1 (Sleepycat) 4/12/97
 *
 * The code appearing below is taken from Richard L. Sites, ed.  "Alpha
 * Architecture Reference Manual", Digital Press, 1992, page 5-7 and 5-8.
 * There are 2 modifications:
 *
 * 1. The jump from blbs __r1,30f to !__r1, which is dictated by the way the
 * TSL_SET macro is used.  The code suggested in Sites includes the main loop
 * of the spin lock, whereas in this code the rest the loop is specified in C.
 * The generated code might be suboptimal if the compiler generates a forward
 * branch for the usual case in which the mutex is uncontested.
 *
 * 2. At label 20, Sites suggests including code for testing for an excessive
 * number of _processor_ lock conflicts.  (The seq_c instruction stores its
 * first argument provided that no other processor has written to a byte range
 * including its memory-location argument.)  Absent such checking the code
 * below could conceivably stall silently on a multiprocessor alpha, depending
 * on how often processor/processor conflicts occur in a particular byte range.
 *
 * Note that the mb ("memory-barrier") instruction in TSL_UNSET is critical to
 * correct operation in a multiprocessor alpha (as is, of course, the mb in
 * the TSL_SET macro).  Without the mb, changes to shared memory that occurred
 * inside the critical section (before the TSL_UNSET) might reach shared memory
 * _after_ the change of tsl to 0, thereby permitting another processor to see
 * an inconsistent view of the data protected by the mutex.
 *
 * For gcc/alpha, 0 is clear, 1 is set.
 */
#define TSL_SET(tsl) ({							\
	register tsl_t *__l = (tsl);					\
	register tsl_t __r1, __r2;					\
	__asm__ volatile("						\n\
	   10: ldq_l %0,(%2)						\n\
	       blbs  %0,30f						\n\
	       or    %0,1,%1						\n\
	       stq_c %1,(%2)						\n\
	       beq   %1,20f						\n\
	       mb							\n\
	       br    30f						\n\
	   20: br    10b						\n\
	   30: "							\
	  : "=&r" (__r1), "=&r" (__r2)					\
	  : "r" (__l));							\
	!__r1;								\
})

#define TSL_UNSET(tsl) ({						\
	register tsl_t *__l = (tsl);					\
	__asm__ volatile("mb; stq $31,(%0);" : : "r" (__l));		\
})
#define	TSL_INIT(tsl)	TSL_UNSET(tsl)
