162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Spinlock support for the Hexagon architecture 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _ASM_SPINLOCK_H 962306a36Sopenharmony_ci#define _ASM_SPINLOCK_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <asm/irqflags.h> 1262306a36Sopenharmony_ci#include <asm/barrier.h> 1362306a36Sopenharmony_ci#include <asm/processor.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * This file is pulled in for SMP builds. 1762306a36Sopenharmony_ci * Really need to check all the barrier stuff for "true" SMP 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * Read locks: 2262306a36Sopenharmony_ci * - load the lock value 2362306a36Sopenharmony_ci * - increment it 2462306a36Sopenharmony_ci * - if the lock value is still negative, go back and try again. 2562306a36Sopenharmony_ci * - unsuccessful store is unsuccessful. Go back and try again. Loser. 2662306a36Sopenharmony_ci * - successful store new lock value if positive -> lock acquired 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_cistatic inline void arch_read_lock(arch_rwlock_t *lock) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci __asm__ __volatile__( 3162306a36Sopenharmony_ci "1: R6 = memw_locked(%0);\n" 3262306a36Sopenharmony_ci " { P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n" 3362306a36Sopenharmony_ci " { if (!P3) jump 1b; }\n" 3462306a36Sopenharmony_ci " memw_locked(%0,P3) = R6;\n" 3562306a36Sopenharmony_ci " { if (!P3) jump 1b; }\n" 3662306a36Sopenharmony_ci : 3762306a36Sopenharmony_ci : "r" (&lock->lock) 3862306a36Sopenharmony_ci : "memory", "r6", "p3" 3962306a36Sopenharmony_ci ); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic inline void arch_read_unlock(arch_rwlock_t *lock) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci __asm__ __volatile__( 4662306a36Sopenharmony_ci "1: R6 = memw_locked(%0);\n" 4762306a36Sopenharmony_ci " R6 = add(R6,#-1);\n" 4862306a36Sopenharmony_ci " memw_locked(%0,P3) = R6\n" 4962306a36Sopenharmony_ci " if (!P3) jump 1b;\n" 5062306a36Sopenharmony_ci : 5162306a36Sopenharmony_ci : "r" (&lock->lock) 5262306a36Sopenharmony_ci : "memory", "r6", "p3" 5362306a36Sopenharmony_ci ); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* I think this returns 0 on fail, 1 on success. */ 5862306a36Sopenharmony_cistatic inline int arch_read_trylock(arch_rwlock_t *lock) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci int temp; 6162306a36Sopenharmony_ci __asm__ __volatile__( 6262306a36Sopenharmony_ci " R6 = memw_locked(%1);\n" 6362306a36Sopenharmony_ci " { %0 = #0; P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n" 6462306a36Sopenharmony_ci " { if (!P3) jump 1f; }\n" 6562306a36Sopenharmony_ci " memw_locked(%1,P3) = R6;\n" 6662306a36Sopenharmony_ci " { %0 = P3 }\n" 6762306a36Sopenharmony_ci "1:\n" 6862306a36Sopenharmony_ci : "=&r" (temp) 6962306a36Sopenharmony_ci : "r" (&lock->lock) 7062306a36Sopenharmony_ci : "memory", "r6", "p3" 7162306a36Sopenharmony_ci ); 7262306a36Sopenharmony_ci return temp; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Stuffs a -1 in the lock value? */ 7662306a36Sopenharmony_cistatic inline void arch_write_lock(arch_rwlock_t *lock) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci __asm__ __volatile__( 7962306a36Sopenharmony_ci "1: R6 = memw_locked(%0)\n" 8062306a36Sopenharmony_ci " { P3 = cmp.eq(R6,#0); R6 = #-1;}\n" 8162306a36Sopenharmony_ci " { if (!P3) jump 1b; }\n" 8262306a36Sopenharmony_ci " memw_locked(%0,P3) = R6;\n" 8362306a36Sopenharmony_ci " { if (!P3) jump 1b; }\n" 8462306a36Sopenharmony_ci : 8562306a36Sopenharmony_ci : "r" (&lock->lock) 8662306a36Sopenharmony_ci : "memory", "r6", "p3" 8762306a36Sopenharmony_ci ); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic inline int arch_write_trylock(arch_rwlock_t *lock) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci int temp; 9462306a36Sopenharmony_ci __asm__ __volatile__( 9562306a36Sopenharmony_ci " R6 = memw_locked(%1)\n" 9662306a36Sopenharmony_ci " { %0 = #0; P3 = cmp.eq(R6,#0); R6 = #-1;}\n" 9762306a36Sopenharmony_ci " { if (!P3) jump 1f; }\n" 9862306a36Sopenharmony_ci " memw_locked(%1,P3) = R6;\n" 9962306a36Sopenharmony_ci " %0 = P3;\n" 10062306a36Sopenharmony_ci "1:\n" 10162306a36Sopenharmony_ci : "=&r" (temp) 10262306a36Sopenharmony_ci : "r" (&lock->lock) 10362306a36Sopenharmony_ci : "memory", "r6", "p3" 10462306a36Sopenharmony_ci ); 10562306a36Sopenharmony_ci return temp; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic inline void arch_write_unlock(arch_rwlock_t *lock) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci smp_mb(); 11262306a36Sopenharmony_ci lock->lock = 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic inline void arch_spin_lock(arch_spinlock_t *lock) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci __asm__ __volatile__( 11862306a36Sopenharmony_ci "1: R6 = memw_locked(%0);\n" 11962306a36Sopenharmony_ci " P3 = cmp.eq(R6,#0);\n" 12062306a36Sopenharmony_ci " { if (!P3) jump 1b; R6 = #1; }\n" 12162306a36Sopenharmony_ci " memw_locked(%0,P3) = R6;\n" 12262306a36Sopenharmony_ci " { if (!P3) jump 1b; }\n" 12362306a36Sopenharmony_ci : 12462306a36Sopenharmony_ci : "r" (&lock->lock) 12562306a36Sopenharmony_ci : "memory", "r6", "p3" 12662306a36Sopenharmony_ci ); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic inline void arch_spin_unlock(arch_spinlock_t *lock) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci smp_mb(); 13362306a36Sopenharmony_ci lock->lock = 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci int temp; 13962306a36Sopenharmony_ci __asm__ __volatile__( 14062306a36Sopenharmony_ci " R6 = memw_locked(%1);\n" 14162306a36Sopenharmony_ci " P3 = cmp.eq(R6,#0);\n" 14262306a36Sopenharmony_ci " { if (!P3) jump 1f; R6 = #1; %0 = #0; }\n" 14362306a36Sopenharmony_ci " memw_locked(%1,P3) = R6;\n" 14462306a36Sopenharmony_ci " %0 = P3;\n" 14562306a36Sopenharmony_ci "1:\n" 14662306a36Sopenharmony_ci : "=&r" (temp) 14762306a36Sopenharmony_ci : "r" (&lock->lock) 14862306a36Sopenharmony_ci : "memory", "r6", "p3" 14962306a36Sopenharmony_ci ); 15062306a36Sopenharmony_ci return temp; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * SMP spinlocks are intended to allow only a single CPU at the lock 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci#define arch_spin_is_locked(x) ((x)->lock != 0) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#endif 159