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