162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2013 Davidlohr Bueso <davidlohr.bueso@hp.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Based on the shift-and-subtract algorithm for computing integer
662306a36Sopenharmony_ci *  square root from Guy L. Steele.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci#include <linux/bitops.h>
1162306a36Sopenharmony_ci#include <linux/limits.h>
1262306a36Sopenharmony_ci#include <linux/math.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/**
1562306a36Sopenharmony_ci * int_sqrt - computes the integer square root
1662306a36Sopenharmony_ci * @x: integer of which to calculate the sqrt
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * Computes: floor(sqrt(x))
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ciunsigned long int_sqrt(unsigned long x)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	unsigned long b, m, y = 0;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	if (x <= 1)
2562306a36Sopenharmony_ci		return x;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	m = 1UL << (__fls(x) & ~1UL);
2862306a36Sopenharmony_ci	while (m != 0) {
2962306a36Sopenharmony_ci		b = y + m;
3062306a36Sopenharmony_ci		y >>= 1;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci		if (x >= b) {
3362306a36Sopenharmony_ci			x -= b;
3462306a36Sopenharmony_ci			y += m;
3562306a36Sopenharmony_ci		}
3662306a36Sopenharmony_ci		m >>= 2;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return y;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ciEXPORT_SYMBOL(int_sqrt);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#if BITS_PER_LONG < 64
4462306a36Sopenharmony_ci/**
4562306a36Sopenharmony_ci * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input
4662306a36Sopenharmony_ci * is expected.
4762306a36Sopenharmony_ci * @x: 64bit integer of which to calculate the sqrt
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ciu32 int_sqrt64(u64 x)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	u64 b, m, y = 0;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (x <= ULONG_MAX)
5462306a36Sopenharmony_ci		return int_sqrt((unsigned long) x);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	m = 1ULL << ((fls64(x) - 1) & ~1ULL);
5762306a36Sopenharmony_ci	while (m != 0) {
5862306a36Sopenharmony_ci		b = y + m;
5962306a36Sopenharmony_ci		y >>= 1;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (x >= b) {
6262306a36Sopenharmony_ci			x -= b;
6362306a36Sopenharmony_ci			y += m;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci		m >>= 2;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return y;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ciEXPORT_SYMBOL(int_sqrt64);
7162306a36Sopenharmony_ci#endif
72