18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef __ASM_QSPINLOCK_PARAVIRT_H 38c2ecf20Sopenharmony_ci#define __ASM_QSPINLOCK_PARAVIRT_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci/* 68c2ecf20Sopenharmony_ci * For x86-64, PV_CALLEE_SAVE_REGS_THUNK() saves and restores 8 64-bit 78c2ecf20Sopenharmony_ci * registers. For i386, however, only 1 32-bit register needs to be saved 88c2ecf20Sopenharmony_ci * and restored. So an optimized version of __pv_queued_spin_unlock() is 98c2ecf20Sopenharmony_ci * hand-coded for 64-bit, but it isn't worthwhile to do it for 32-bit. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciPV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock_slowpath); 148c2ecf20Sopenharmony_ci#define __pv_queued_spin_unlock __pv_queued_spin_unlock 158c2ecf20Sopenharmony_ci#define PV_UNLOCK "__raw_callee_save___pv_queued_spin_unlock" 168c2ecf20Sopenharmony_ci#define PV_UNLOCK_SLOWPATH "__raw_callee_save___pv_queued_spin_unlock_slowpath" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* 198c2ecf20Sopenharmony_ci * Optimized assembly version of __raw_callee_save___pv_queued_spin_unlock 208c2ecf20Sopenharmony_ci * which combines the registers saving trunk and the body of the following 218c2ecf20Sopenharmony_ci * C code: 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * void __pv_queued_spin_unlock(struct qspinlock *lock) 248c2ecf20Sopenharmony_ci * { 258c2ecf20Sopenharmony_ci * u8 lockval = cmpxchg(&lock->locked, _Q_LOCKED_VAL, 0); 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * if (likely(lockval == _Q_LOCKED_VAL)) 288c2ecf20Sopenharmony_ci * return; 298c2ecf20Sopenharmony_ci * pv_queued_spin_unlock_slowpath(lock, lockval); 308c2ecf20Sopenharmony_ci * } 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * For x86-64, 338c2ecf20Sopenharmony_ci * rdi = lock (first argument) 348c2ecf20Sopenharmony_ci * rsi = lockval (second argument) 358c2ecf20Sopenharmony_ci * rdx = internal variable (set to 0) 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ciasm (".pushsection .text;" 388c2ecf20Sopenharmony_ci ".globl " PV_UNLOCK ";" 398c2ecf20Sopenharmony_ci ".type " PV_UNLOCK ", @function;" 408c2ecf20Sopenharmony_ci ".align 4,0x90;" 418c2ecf20Sopenharmony_ci PV_UNLOCK ": " 428c2ecf20Sopenharmony_ci FRAME_BEGIN 438c2ecf20Sopenharmony_ci "push %rdx;" 448c2ecf20Sopenharmony_ci "mov $0x1,%eax;" 458c2ecf20Sopenharmony_ci "xor %edx,%edx;" 468c2ecf20Sopenharmony_ci LOCK_PREFIX "cmpxchg %dl,(%rdi);" 478c2ecf20Sopenharmony_ci "cmp $0x1,%al;" 488c2ecf20Sopenharmony_ci "jne .slowpath;" 498c2ecf20Sopenharmony_ci "pop %rdx;" 508c2ecf20Sopenharmony_ci FRAME_END 518c2ecf20Sopenharmony_ci ASM_RET 528c2ecf20Sopenharmony_ci ".slowpath: " 538c2ecf20Sopenharmony_ci "push %rsi;" 548c2ecf20Sopenharmony_ci "movzbl %al,%esi;" 558c2ecf20Sopenharmony_ci "call " PV_UNLOCK_SLOWPATH ";" 568c2ecf20Sopenharmony_ci "pop %rsi;" 578c2ecf20Sopenharmony_ci "pop %rdx;" 588c2ecf20Sopenharmony_ci FRAME_END 598c2ecf20Sopenharmony_ci ASM_RET 608c2ecf20Sopenharmony_ci ".size " PV_UNLOCK ", .-" PV_UNLOCK ";" 618c2ecf20Sopenharmony_ci ".popsection"); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#else /* CONFIG_64BIT */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciextern void __pv_queued_spin_unlock(struct qspinlock *lock); 668c2ecf20Sopenharmony_ciPV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#endif /* CONFIG_64BIT */ 698c2ecf20Sopenharmony_ci#endif 70