1*b2441318SGreg 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