18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * bitext.c: kernel little helper (of bit shuffling variety).
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2002 Pete Zaitcev <zaitcev@yahoo.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * The algorithm to search a zero bit string is geared towards its application.
88c2ecf20Sopenharmony_ci * We expect a couple of fixed sizes of requests, so a rotating counter, reset
98c2ecf20Sopenharmony_ci * by align size, should provide fast enough search while maintaining low
108c2ecf20Sopenharmony_ci * fragmentation.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/string.h>
148c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <asm/bitext.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/**
198c2ecf20Sopenharmony_ci * bit_map_string_get - find and set a bit string in bit map.
208c2ecf20Sopenharmony_ci * @t: the bit map.
218c2ecf20Sopenharmony_ci * @len: requested string length
228c2ecf20Sopenharmony_ci * @align: requested alignment
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Returns offset in the map or -1 if out of space.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Not safe to call from an interrupt (uses spin_lock).
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ciint bit_map_string_get(struct bit_map *t, int len, int align)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	int offset, count;	/* siamese twins */
318c2ecf20Sopenharmony_ci	int off_new;
328c2ecf20Sopenharmony_ci	int align1;
338c2ecf20Sopenharmony_ci	int i, color;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (t->num_colors) {
368c2ecf20Sopenharmony_ci		/* align is overloaded to be the page color */
378c2ecf20Sopenharmony_ci		color = align;
388c2ecf20Sopenharmony_ci		align = t->num_colors;
398c2ecf20Sopenharmony_ci	} else {
408c2ecf20Sopenharmony_ci		color = 0;
418c2ecf20Sopenharmony_ci		if (align == 0)
428c2ecf20Sopenharmony_ci			align = 1;
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci	align1 = align - 1;
458c2ecf20Sopenharmony_ci	if ((align & align1) != 0)
468c2ecf20Sopenharmony_ci		BUG();
478c2ecf20Sopenharmony_ci	if (align < 0 || align >= t->size)
488c2ecf20Sopenharmony_ci		BUG();
498c2ecf20Sopenharmony_ci	if (len <= 0 || len > t->size)
508c2ecf20Sopenharmony_ci		BUG();
518c2ecf20Sopenharmony_ci	color &= align1;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	spin_lock(&t->lock);
548c2ecf20Sopenharmony_ci	if (len < t->last_size)
558c2ecf20Sopenharmony_ci		offset = t->first_free;
568c2ecf20Sopenharmony_ci	else
578c2ecf20Sopenharmony_ci		offset = t->last_off & ~align1;
588c2ecf20Sopenharmony_ci	count = 0;
598c2ecf20Sopenharmony_ci	for (;;) {
608c2ecf20Sopenharmony_ci		off_new = find_next_zero_bit(t->map, t->size, offset);
618c2ecf20Sopenharmony_ci		off_new = ((off_new + align1) & ~align1) + color;
628c2ecf20Sopenharmony_ci		count += off_new - offset;
638c2ecf20Sopenharmony_ci		offset = off_new;
648c2ecf20Sopenharmony_ci		if (offset >= t->size)
658c2ecf20Sopenharmony_ci			offset = 0;
668c2ecf20Sopenharmony_ci		if (count + len > t->size) {
678c2ecf20Sopenharmony_ci			spin_unlock(&t->lock);
688c2ecf20Sopenharmony_ci/* P3 */ printk(KERN_ERR
698c2ecf20Sopenharmony_ci  "bitmap out: size %d used %d off %d len %d align %d count %d\n",
708c2ecf20Sopenharmony_ci  t->size, t->used, offset, len, align, count);
718c2ecf20Sopenharmony_ci			return -1;
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		if (offset + len > t->size) {
758c2ecf20Sopenharmony_ci			count += t->size - offset;
768c2ecf20Sopenharmony_ci			offset = 0;
778c2ecf20Sopenharmony_ci			continue;
788c2ecf20Sopenharmony_ci		}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		i = 0;
818c2ecf20Sopenharmony_ci		while (test_bit(offset + i, t->map) == 0) {
828c2ecf20Sopenharmony_ci			i++;
838c2ecf20Sopenharmony_ci			if (i == len) {
848c2ecf20Sopenharmony_ci				bitmap_set(t->map, offset, len);
858c2ecf20Sopenharmony_ci				if (offset == t->first_free)
868c2ecf20Sopenharmony_ci					t->first_free = find_next_zero_bit
878c2ecf20Sopenharmony_ci							(t->map, t->size,
888c2ecf20Sopenharmony_ci							 t->first_free + len);
898c2ecf20Sopenharmony_ci				if ((t->last_off = offset + len) >= t->size)
908c2ecf20Sopenharmony_ci					t->last_off = 0;
918c2ecf20Sopenharmony_ci				t->used += len;
928c2ecf20Sopenharmony_ci				t->last_size = len;
938c2ecf20Sopenharmony_ci				spin_unlock(&t->lock);
948c2ecf20Sopenharmony_ci				return offset;
958c2ecf20Sopenharmony_ci			}
968c2ecf20Sopenharmony_ci		}
978c2ecf20Sopenharmony_ci		count += i + 1;
988c2ecf20Sopenharmony_ci		if ((offset += i + 1) >= t->size)
998c2ecf20Sopenharmony_ci			offset = 0;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_civoid bit_map_clear(struct bit_map *t, int offset, int len)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int i;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (t->used < len)
1088c2ecf20Sopenharmony_ci		BUG();		/* Much too late to do any good, but alas... */
1098c2ecf20Sopenharmony_ci	spin_lock(&t->lock);
1108c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
1118c2ecf20Sopenharmony_ci		if (test_bit(offset + i, t->map) == 0)
1128c2ecf20Sopenharmony_ci			BUG();
1138c2ecf20Sopenharmony_ci		__clear_bit(offset + i, t->map);
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	if (offset < t->first_free)
1168c2ecf20Sopenharmony_ci		t->first_free = offset;
1178c2ecf20Sopenharmony_ci	t->used -= len;
1188c2ecf20Sopenharmony_ci	spin_unlock(&t->lock);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_civoid bit_map_init(struct bit_map *t, unsigned long *map, int size)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	bitmap_zero(map, size);
1248c2ecf20Sopenharmony_ci	memset(t, 0, sizeof *t);
1258c2ecf20Sopenharmony_ci	spin_lock_init(&t->lock);
1268c2ecf20Sopenharmony_ci	t->map = map;
1278c2ecf20Sopenharmony_ci	t->size = size;
1288c2ecf20Sopenharmony_ci}
129