162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef __ASM_ARM_DIV64 362306a36Sopenharmony_ci#define __ASM_ARM_DIV64 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <asm/compiler.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * The semantics of __div64_32() are: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * uint32_t __div64_32(uint64_t *n, uint32_t base) 1262306a36Sopenharmony_ci * { 1362306a36Sopenharmony_ci * uint32_t remainder = *n % base; 1462306a36Sopenharmony_ci * *n = *n / base; 1562306a36Sopenharmony_ci * return remainder; 1662306a36Sopenharmony_ci * } 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * In other words, a 64-bit dividend with a 32-bit divisor producing 1962306a36Sopenharmony_ci * a 64-bit result and a 32-bit remainder. To accomplish this optimally 2062306a36Sopenharmony_ci * we override the generic version in lib/div64.c to call our __do_div64 2162306a36Sopenharmony_ci * assembly implementation with completely non standard calling convention 2262306a36Sopenharmony_ci * for arguments and results (beware). 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cistatic inline uint32_t __div64_32(uint64_t *n, uint32_t base) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci register unsigned int __base asm("r4") = base; 2762306a36Sopenharmony_ci register unsigned long long __n asm("r0") = *n; 2862306a36Sopenharmony_ci register unsigned long long __res asm("r2"); 2962306a36Sopenharmony_ci unsigned int __rem; 3062306a36Sopenharmony_ci asm( __asmeq("%0", "r0") 3162306a36Sopenharmony_ci __asmeq("%1", "r2") 3262306a36Sopenharmony_ci __asmeq("%2", "r4") 3362306a36Sopenharmony_ci "bl __do_div64" 3462306a36Sopenharmony_ci : "+r" (__n), "=r" (__res) 3562306a36Sopenharmony_ci : "r" (__base) 3662306a36Sopenharmony_ci : "ip", "lr", "cc"); 3762306a36Sopenharmony_ci __rem = __n >> 32; 3862306a36Sopenharmony_ci *n = __res; 3962306a36Sopenharmony_ci return __rem; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci#define __div64_32 __div64_32 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#if !defined(CONFIG_AEABI) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * In OABI configurations, some uses of the do_div function 4762306a36Sopenharmony_ci * cause gcc to run out of registers. To work around that, 4862306a36Sopenharmony_ci * we can force the use of the out-of-line version for 4962306a36Sopenharmony_ci * configurations that build a OABI kernel. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci#define do_div(n, base) __div64_32(&(n), base) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#else 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci unsigned long long res; 5862306a36Sopenharmony_ci register unsigned int tmp asm("ip") = 0; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (!bias) { 6162306a36Sopenharmony_ci asm ( "umull %Q0, %R0, %Q1, %Q2\n\t" 6262306a36Sopenharmony_ci "mov %Q0, #0" 6362306a36Sopenharmony_ci : "=&r" (res) 6462306a36Sopenharmony_ci : "r" (m), "r" (n) 6562306a36Sopenharmony_ci : "cc"); 6662306a36Sopenharmony_ci } else if (!(m & ((1ULL << 63) | (1ULL << 31)))) { 6762306a36Sopenharmony_ci res = m; 6862306a36Sopenharmony_ci asm ( "umlal %Q0, %R0, %Q1, %Q2\n\t" 6962306a36Sopenharmony_ci "mov %Q0, #0" 7062306a36Sopenharmony_ci : "+&r" (res) 7162306a36Sopenharmony_ci : "r" (m), "r" (n) 7262306a36Sopenharmony_ci : "cc"); 7362306a36Sopenharmony_ci } else { 7462306a36Sopenharmony_ci asm ( "umull %Q0, %R0, %Q2, %Q3\n\t" 7562306a36Sopenharmony_ci "cmn %Q0, %Q2\n\t" 7662306a36Sopenharmony_ci "adcs %R0, %R0, %R2\n\t" 7762306a36Sopenharmony_ci "adc %Q0, %1, #0" 7862306a36Sopenharmony_ci : "=&r" (res), "+&r" (tmp) 7962306a36Sopenharmony_ci : "r" (m), "r" (n) 8062306a36Sopenharmony_ci : "cc"); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (!(m & ((1ULL << 63) | (1ULL << 31)))) { 8462306a36Sopenharmony_ci asm ( "umlal %R0, %Q0, %R1, %Q2\n\t" 8562306a36Sopenharmony_ci "umlal %R0, %Q0, %Q1, %R2\n\t" 8662306a36Sopenharmony_ci "mov %R0, #0\n\t" 8762306a36Sopenharmony_ci "umlal %Q0, %R0, %R1, %R2" 8862306a36Sopenharmony_ci : "+&r" (res) 8962306a36Sopenharmony_ci : "r" (m), "r" (n) 9062306a36Sopenharmony_ci : "cc"); 9162306a36Sopenharmony_ci } else { 9262306a36Sopenharmony_ci asm ( "umlal %R0, %Q0, %R2, %Q3\n\t" 9362306a36Sopenharmony_ci "umlal %R0, %1, %Q2, %R3\n\t" 9462306a36Sopenharmony_ci "mov %R0, #0\n\t" 9562306a36Sopenharmony_ci "adds %Q0, %1, %Q0\n\t" 9662306a36Sopenharmony_ci "adc %R0, %R0, #0\n\t" 9762306a36Sopenharmony_ci "umlal %Q0, %R0, %R2, %R3" 9862306a36Sopenharmony_ci : "+&r" (res), "+&r" (tmp) 9962306a36Sopenharmony_ci : "r" (m), "r" (n) 10062306a36Sopenharmony_ci : "cc"); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return res; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci#define __arch_xprod_64 __arch_xprod_64 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#include <asm-generic/div64.h> 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#endif 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#endif 112