/* (C) Rusty Russell <rusty@rustcorp.com.au> */
/* Stolen from Linux kernel (Paul Mackerras) */

/* Atomic dec: return 1 unless counter decremented to zero.
 */
static __inline__ int __down(int *c)
{
	int val;

	/* The isync here stops the chip from pulling loads inside the
           lock above this code */
	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# __down\n\
	addic	%0,%0,-1\n\
	stwcx.	%0,0,%1\n\
	bne-	1b\n\
	isync"
	: "=&r" (val)
	: "r" (c)
	: "cc", "memory");

	return (val != 0);
}

/* Atomic inc: return 1 unless counter incremented from 0 to 1. */
static __inline__ int __up(int *c)
{
	int val;

	/* FIXME: simplify: if we fail, don't loop, just return 1 --RR*/
	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# __up\n\
	addic	%0,%0,1\n\
	stwcx.	%0,0,%1\n\
	bne-	1b\n\
	isync"
	: "=&r" (val)
	: "r" (c)
	: "cc", "memory");

	return (val != 1);
}

/* Commit the write, so it happens before we send the semaphore to
   anyone else */
static __inline__ void __commit(void)
{
	__asm__ __volatile__ ("sync" : : : "memory");
}
