Commit a12ee234 authored by Babu Moger's avatar Babu Moger Committed by David S. Miller
Browse files

arch/sparc: Introduce cmpxchg_u8 SPARC



SPARC supports 32 bit and 64 bit cmpxchg right now. Add support
for 8 bit (1 byte) cmpxchg. This is required to support queued
rwlocks feature  which uses 1 byte cmpxchg.

The function __cmpxchg_u8 here uses the 4 byte cas instruction with a
byte manipulation to achieve 1 byte cmpxchg.

Signed-off-by: default avatarBabu Moger <babu.moger@oracle.com>
Reviewed-by: default avatarHåkon Bugge <haakon.bugge@oracle.com>
Reviewed-by: default avatarSteve Sistare <steven.sistare@oracle.com>
Reviewed-by: default avatarShannon Nelson <shannon.nelson@oracle.com>
Reviewed-by: default avatarJane Chu <jane.chu@oracle.com>
Reviewed-by: default avatarVijay Kumar <vijay.ac.kumar@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 97d9f969
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -87,6 +87,33 @@ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
	return new;
}

/*
 * Use 4 byte cas instruction to achieve 1 byte cmpxchg. Main logic
 * here is to get the bit shift of the byte we are interested in.
 * The XOR is handy for reversing the bits for big-endian byte order
 */
static inline unsigned long
__cmpxchg_u8(volatile unsigned char *m, unsigned char old, unsigned char new)
{
	unsigned long maddr = (unsigned long)m;
	int bit_shift = (((unsigned long)m & 3) ^ 3) << 3;
	unsigned int mask = 0xff << bit_shift;
	unsigned int *ptr = (unsigned int *) (maddr & ~3);
	unsigned int old32, new32, load;
	unsigned int load32 = *ptr;

	do {
		new32 = (load32 & ~mask) | (new << bit_shift);
		old32 = (load32 & ~mask) | (old << bit_shift);
		load32 = __cmpxchg_u32(ptr, old32, new32);
		if (load32 == old32)
			return old;
		load = (load32 & mask) >> bit_shift;
	} while (load == old);

	return load;
}

/* This function doesn't exist, so you'll get a linker error
   if something tries to do an invalid cmpxchg().  */
void __cmpxchg_called_with_bad_pointer(void);
@@ -95,6 +122,8 @@ static inline unsigned long
__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
{
	switch (size) {
		case 1:
			return __cmpxchg_u8(ptr, old, new);
		case 4:
			return __cmpxchg_u32(ptr, old, new);
		case 8: