xref: /openbmc/linux/arch/sparc/lib/bitext.c (revision b2441318)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * bitext.c: kernel little helper (of bit shuffling variety).
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 2002 Pete Zaitcev <zaitcev@yahoo.com>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * The algorithm to search a zero bit string is geared towards its application.
81da177e4SLinus Torvalds  * We expect a couple of fixed sizes of requests, so a rotating counter, reset
91da177e4SLinus Torvalds  * by align size, should provide fast enough search while maintaining low
101da177e4SLinus Torvalds  * fragmentation.
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
13f037360fSAl Viro #include <linux/string.h>
14e637804cSAkinobu Mita #include <linux/bitmap.h>
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include <asm/bitext.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds /**
191da177e4SLinus Torvalds  * bit_map_string_get - find and set a bit string in bit map.
201da177e4SLinus Torvalds  * @t: the bit map.
211da177e4SLinus Torvalds  * @len: requested string length
221da177e4SLinus Torvalds  * @align: requested alignment
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  * Returns offset in the map or -1 if out of space.
251da177e4SLinus Torvalds  *
261da177e4SLinus Torvalds  * Not safe to call from an interrupt (uses spin_lock).
271da177e4SLinus Torvalds  */
bit_map_string_get(struct bit_map * t,int len,int align)281da177e4SLinus Torvalds int bit_map_string_get(struct bit_map *t, int len, int align)
291da177e4SLinus Torvalds {
301da177e4SLinus Torvalds 	int offset, count;	/* siamese twins */
311da177e4SLinus Torvalds 	int off_new;
321da177e4SLinus Torvalds 	int align1;
331da177e4SLinus Torvalds 	int i, color;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 	if (t->num_colors) {
361da177e4SLinus Torvalds 		/* align is overloaded to be the page color */
371da177e4SLinus Torvalds 		color = align;
381da177e4SLinus Torvalds 		align = t->num_colors;
391da177e4SLinus Torvalds 	} else {
401da177e4SLinus Torvalds 		color = 0;
411da177e4SLinus Torvalds 		if (align == 0)
421da177e4SLinus Torvalds 			align = 1;
431da177e4SLinus Torvalds 	}
441da177e4SLinus Torvalds 	align1 = align - 1;
451da177e4SLinus Torvalds 	if ((align & align1) != 0)
461da177e4SLinus Torvalds 		BUG();
471da177e4SLinus Torvalds 	if (align < 0 || align >= t->size)
481da177e4SLinus Torvalds 		BUG();
491da177e4SLinus Torvalds 	if (len <= 0 || len > t->size)
501da177e4SLinus Torvalds 		BUG();
511da177e4SLinus Torvalds 	color &= align1;
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 	spin_lock(&t->lock);
541da177e4SLinus Torvalds 	if (len < t->last_size)
551da177e4SLinus Torvalds 		offset = t->first_free;
561da177e4SLinus Torvalds 	else
571da177e4SLinus Torvalds 		offset = t->last_off & ~align1;
581da177e4SLinus Torvalds 	count = 0;
591da177e4SLinus Torvalds 	for (;;) {
601da177e4SLinus Torvalds 		off_new = find_next_zero_bit(t->map, t->size, offset);
611da177e4SLinus Torvalds 		off_new = ((off_new + align1) & ~align1) + color;
621da177e4SLinus Torvalds 		count += off_new - offset;
631da177e4SLinus Torvalds 		offset = off_new;
641da177e4SLinus Torvalds 		if (offset >= t->size)
651da177e4SLinus Torvalds 			offset = 0;
661da177e4SLinus Torvalds 		if (count + len > t->size) {
671da177e4SLinus Torvalds 			spin_unlock(&t->lock);
681da177e4SLinus Torvalds /* P3 */ printk(KERN_ERR
691da177e4SLinus Torvalds   "bitmap out: size %d used %d off %d len %d align %d count %d\n",
701da177e4SLinus Torvalds   t->size, t->used, offset, len, align, count);
711da177e4SLinus Torvalds 			return -1;
721da177e4SLinus Torvalds 		}
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 		if (offset + len > t->size) {
751da177e4SLinus Torvalds 			count += t->size - offset;
761da177e4SLinus Torvalds 			offset = 0;
771da177e4SLinus Torvalds 			continue;
781da177e4SLinus Torvalds 		}
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 		i = 0;
811da177e4SLinus Torvalds 		while (test_bit(offset + i, t->map) == 0) {
821da177e4SLinus Torvalds 			i++;
831da177e4SLinus Torvalds 			if (i == len) {
84e637804cSAkinobu Mita 				bitmap_set(t->map, offset, len);
851da177e4SLinus Torvalds 				if (offset == t->first_free)
861da177e4SLinus Torvalds 					t->first_free = find_next_zero_bit
871da177e4SLinus Torvalds 							(t->map, t->size,
881da177e4SLinus Torvalds 							 t->first_free + len);
891da177e4SLinus Torvalds 				if ((t->last_off = offset + len) >= t->size)
901da177e4SLinus Torvalds 					t->last_off = 0;
911da177e4SLinus Torvalds 				t->used += len;
921da177e4SLinus Torvalds 				t->last_size = len;
931da177e4SLinus Torvalds 				spin_unlock(&t->lock);
941da177e4SLinus Torvalds 				return offset;
951da177e4SLinus Torvalds 			}
961da177e4SLinus Torvalds 		}
971da177e4SLinus Torvalds 		count += i + 1;
981da177e4SLinus Torvalds 		if ((offset += i + 1) >= t->size)
991da177e4SLinus Torvalds 			offset = 0;
1001da177e4SLinus Torvalds 	}
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds 
bit_map_clear(struct bit_map * t,int offset,int len)1031da177e4SLinus Torvalds void bit_map_clear(struct bit_map *t, int offset, int len)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds 	int i;
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	if (t->used < len)
1081da177e4SLinus Torvalds 		BUG();		/* Much too late to do any good, but alas... */
1091da177e4SLinus Torvalds 	spin_lock(&t->lock);
1101da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
1111da177e4SLinus Torvalds 		if (test_bit(offset + i, t->map) == 0)
1121da177e4SLinus Torvalds 			BUG();
1131da177e4SLinus Torvalds 		__clear_bit(offset + i, t->map);
1141da177e4SLinus Torvalds 	}
1151da177e4SLinus Torvalds 	if (offset < t->first_free)
1161da177e4SLinus Torvalds 		t->first_free = offset;
1171da177e4SLinus Torvalds 	t->used -= len;
1181da177e4SLinus Torvalds 	spin_unlock(&t->lock);
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds 
bit_map_init(struct bit_map * t,unsigned long * map,int size)1211da177e4SLinus Torvalds void bit_map_init(struct bit_map *t, unsigned long *map, int size)
1221da177e4SLinus Torvalds {
12354df2db3SAkinobu Mita 	bitmap_zero(map, size);
1241da177e4SLinus Torvalds 	memset(t, 0, sizeof *t);
1251da177e4SLinus Torvalds 	spin_lock_init(&t->lock);
1261da177e4SLinus Torvalds 	t->map = map;
1271da177e4SLinus Torvalds 	t->size = size;
1281da177e4SLinus Torvalds }
129