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