162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/export.h> 662306a36Sopenharmony_ci#include <linux/libgcc.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define W_TYPE_SIZE 32 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2)) 1162306a36Sopenharmony_ci#define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1)) 1262306a36Sopenharmony_ci#define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2)) 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* If we still don't have umul_ppmm, define it using plain C. */ 1562306a36Sopenharmony_ci#if !defined(umul_ppmm) 1662306a36Sopenharmony_ci#define umul_ppmm(w1, w0, u, v) \ 1762306a36Sopenharmony_ci do { \ 1862306a36Sopenharmony_ci unsigned long __x0, __x1, __x2, __x3; \ 1962306a36Sopenharmony_ci unsigned short __ul, __vl, __uh, __vh; \ 2062306a36Sopenharmony_ci \ 2162306a36Sopenharmony_ci __ul = __ll_lowpart(u); \ 2262306a36Sopenharmony_ci __uh = __ll_highpart(u); \ 2362306a36Sopenharmony_ci __vl = __ll_lowpart(v); \ 2462306a36Sopenharmony_ci __vh = __ll_highpart(v); \ 2562306a36Sopenharmony_ci \ 2662306a36Sopenharmony_ci __x0 = (unsigned long) __ul * __vl; \ 2762306a36Sopenharmony_ci __x1 = (unsigned long) __ul * __vh; \ 2862306a36Sopenharmony_ci __x2 = (unsigned long) __uh * __vl; \ 2962306a36Sopenharmony_ci __x3 = (unsigned long) __uh * __vh; \ 3062306a36Sopenharmony_ci \ 3162306a36Sopenharmony_ci __x1 += __ll_highpart(__x0); /* this can't give carry */\ 3262306a36Sopenharmony_ci __x1 += __x2; /* but this indeed can */ \ 3362306a36Sopenharmony_ci if (__x1 < __x2) /* did we get it? */ \ 3462306a36Sopenharmony_ci __x3 += __ll_B; /* yes, add it in the proper pos */ \ 3562306a36Sopenharmony_ci \ 3662306a36Sopenharmony_ci (w1) = __x3 + __ll_highpart(__x1); \ 3762306a36Sopenharmony_ci (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\ 3862306a36Sopenharmony_ci } while (0) 3962306a36Sopenharmony_ci#endif 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#if !defined(__umulsidi3) 4262306a36Sopenharmony_ci#define __umulsidi3(u, v) ({ \ 4362306a36Sopenharmony_ci DWunion __w; \ 4462306a36Sopenharmony_ci umul_ppmm(__w.s.high, __w.s.low, u, v); \ 4562306a36Sopenharmony_ci __w.ll; \ 4662306a36Sopenharmony_ci }) 4762306a36Sopenharmony_ci#endif 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cilong long notrace __muldi3(long long u, long long v) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci const DWunion uu = {.ll = u}; 5262306a36Sopenharmony_ci const DWunion vv = {.ll = v}; 5362306a36Sopenharmony_ci DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci w.s.high += ((unsigned long) uu.s.low * (unsigned long) vv.s.high 5662306a36Sopenharmony_ci + (unsigned long) uu.s.high * (unsigned long) vv.s.low); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return w.ll; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ciEXPORT_SYMBOL(__muldi3); 61