18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/export.h>
38c2ecf20Sopenharmony_ci#include <linux/bug.h>
48c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/**
78c2ecf20Sopenharmony_ci * memweight - count the total number of bits set in memory area
88c2ecf20Sopenharmony_ci * @ptr: pointer to the start of the area
98c2ecf20Sopenharmony_ci * @bytes: the size of the area
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_cisize_t memweight(const void *ptr, size_t bytes)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	size_t ret = 0;
148c2ecf20Sopenharmony_ci	size_t longs;
158c2ecf20Sopenharmony_ci	const unsigned char *bitmap = ptr;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	for (; bytes > 0 && ((unsigned long)bitmap) % sizeof(long);
188c2ecf20Sopenharmony_ci			bytes--, bitmap++)
198c2ecf20Sopenharmony_ci		ret += hweight8(*bitmap);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	longs = bytes / sizeof(long);
228c2ecf20Sopenharmony_ci	if (longs) {
238c2ecf20Sopenharmony_ci		BUG_ON(longs >= INT_MAX / BITS_PER_LONG);
248c2ecf20Sopenharmony_ci		ret += bitmap_weight((unsigned long *)bitmap,
258c2ecf20Sopenharmony_ci				longs * BITS_PER_LONG);
268c2ecf20Sopenharmony_ci		bytes -= longs * sizeof(long);
278c2ecf20Sopenharmony_ci		bitmap += longs * sizeof(long);
288c2ecf20Sopenharmony_ci	}
298c2ecf20Sopenharmony_ci	/*
308c2ecf20Sopenharmony_ci	 * The reason that this last loop is distinct from the preceding
318c2ecf20Sopenharmony_ci	 * bitmap_weight() call is to compute 1-bits in the last region smaller
328c2ecf20Sopenharmony_ci	 * than sizeof(long) properly on big-endian systems.
338c2ecf20Sopenharmony_ci	 */
348c2ecf20Sopenharmony_ci	for (; bytes > 0; bytes--, bitmap++)
358c2ecf20Sopenharmony_ci		ret += hweight8(*bitmap);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return ret;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memweight);
40