xref: /openbmc/linux/lib/sbitmap.c (revision 88459642cba452630326b9cab1c651e09577d4e4)
1*88459642SOmar Sandoval /*
2*88459642SOmar Sandoval  * Copyright (C) 2016 Facebook
3*88459642SOmar Sandoval  * Copyright (C) 2013-2014 Jens Axboe
4*88459642SOmar Sandoval  *
5*88459642SOmar Sandoval  * This program is free software; you can redistribute it and/or
6*88459642SOmar Sandoval  * modify it under the terms of the GNU General Public
7*88459642SOmar Sandoval  * License v2 as published by the Free Software Foundation.
8*88459642SOmar Sandoval  *
9*88459642SOmar Sandoval  * This program is distributed in the hope that it will be useful,
10*88459642SOmar Sandoval  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*88459642SOmar Sandoval  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12*88459642SOmar Sandoval  * General Public License for more details.
13*88459642SOmar Sandoval  *
14*88459642SOmar Sandoval  * You should have received a copy of the GNU General Public License
15*88459642SOmar Sandoval  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16*88459642SOmar Sandoval  */
17*88459642SOmar Sandoval 
18*88459642SOmar Sandoval #include <linux/sbitmap.h>
19*88459642SOmar Sandoval 
20*88459642SOmar Sandoval int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift,
21*88459642SOmar Sandoval 		      gfp_t flags, int node)
22*88459642SOmar Sandoval {
23*88459642SOmar Sandoval 	unsigned int bits_per_word;
24*88459642SOmar Sandoval 	unsigned int i;
25*88459642SOmar Sandoval 
26*88459642SOmar Sandoval 	if (shift < 0) {
27*88459642SOmar Sandoval 		shift = ilog2(BITS_PER_LONG);
28*88459642SOmar Sandoval 		/*
29*88459642SOmar Sandoval 		 * If the bitmap is small, shrink the number of bits per word so
30*88459642SOmar Sandoval 		 * we spread over a few cachelines, at least. If less than 4
31*88459642SOmar Sandoval 		 * bits, just forget about it, it's not going to work optimally
32*88459642SOmar Sandoval 		 * anyway.
33*88459642SOmar Sandoval 		 */
34*88459642SOmar Sandoval 		if (depth >= 4) {
35*88459642SOmar Sandoval 			while ((4U << shift) > depth)
36*88459642SOmar Sandoval 				shift--;
37*88459642SOmar Sandoval 		}
38*88459642SOmar Sandoval 	}
39*88459642SOmar Sandoval 	bits_per_word = 1U << shift;
40*88459642SOmar Sandoval 	if (bits_per_word > BITS_PER_LONG)
41*88459642SOmar Sandoval 		return -EINVAL;
42*88459642SOmar Sandoval 
43*88459642SOmar Sandoval 	sb->shift = shift;
44*88459642SOmar Sandoval 	sb->depth = depth;
45*88459642SOmar Sandoval 	sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word);
46*88459642SOmar Sandoval 
47*88459642SOmar Sandoval 	if (depth == 0) {
48*88459642SOmar Sandoval 		sb->map = NULL;
49*88459642SOmar Sandoval 		return 0;
50*88459642SOmar Sandoval 	}
51*88459642SOmar Sandoval 
52*88459642SOmar Sandoval 	sb->map = kzalloc_node(sb->map_nr * sizeof(*sb->map), flags, node);
53*88459642SOmar Sandoval 	if (!sb->map)
54*88459642SOmar Sandoval 		return -ENOMEM;
55*88459642SOmar Sandoval 
56*88459642SOmar Sandoval 	for (i = 0; i < sb->map_nr; i++) {
57*88459642SOmar Sandoval 		sb->map[i].depth = min(depth, bits_per_word);
58*88459642SOmar Sandoval 		depth -= sb->map[i].depth;
59*88459642SOmar Sandoval 	}
60*88459642SOmar Sandoval 	return 0;
61*88459642SOmar Sandoval }
62*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_init_node);
63*88459642SOmar Sandoval 
64*88459642SOmar Sandoval void sbitmap_resize(struct sbitmap *sb, unsigned int depth)
65*88459642SOmar Sandoval {
66*88459642SOmar Sandoval 	unsigned int bits_per_word = 1U << sb->shift;
67*88459642SOmar Sandoval 	unsigned int i;
68*88459642SOmar Sandoval 
69*88459642SOmar Sandoval 	sb->depth = depth;
70*88459642SOmar Sandoval 	sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word);
71*88459642SOmar Sandoval 
72*88459642SOmar Sandoval 	for (i = 0; i < sb->map_nr; i++) {
73*88459642SOmar Sandoval 		sb->map[i].depth = min(depth, bits_per_word);
74*88459642SOmar Sandoval 		depth -= sb->map[i].depth;
75*88459642SOmar Sandoval 	}
76*88459642SOmar Sandoval }
77*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_resize);
78*88459642SOmar Sandoval 
79*88459642SOmar Sandoval static int __sbitmap_get_word(struct sbitmap_word *word, unsigned int hint,
80*88459642SOmar Sandoval 			      bool wrap)
81*88459642SOmar Sandoval {
82*88459642SOmar Sandoval 	unsigned int orig_hint = hint;
83*88459642SOmar Sandoval 	int nr;
84*88459642SOmar Sandoval 
85*88459642SOmar Sandoval 	while (1) {
86*88459642SOmar Sandoval 		nr = find_next_zero_bit(&word->word, word->depth, hint);
87*88459642SOmar Sandoval 		if (unlikely(nr >= word->depth)) {
88*88459642SOmar Sandoval 			/*
89*88459642SOmar Sandoval 			 * We started with an offset, and we didn't reset the
90*88459642SOmar Sandoval 			 * offset to 0 in a failure case, so start from 0 to
91*88459642SOmar Sandoval 			 * exhaust the map.
92*88459642SOmar Sandoval 			 */
93*88459642SOmar Sandoval 			if (orig_hint && hint && wrap) {
94*88459642SOmar Sandoval 				hint = orig_hint = 0;
95*88459642SOmar Sandoval 				continue;
96*88459642SOmar Sandoval 			}
97*88459642SOmar Sandoval 			return -1;
98*88459642SOmar Sandoval 		}
99*88459642SOmar Sandoval 
100*88459642SOmar Sandoval 		if (!test_and_set_bit(nr, &word->word))
101*88459642SOmar Sandoval 			break;
102*88459642SOmar Sandoval 
103*88459642SOmar Sandoval 		hint = nr + 1;
104*88459642SOmar Sandoval 		if (hint >= word->depth - 1)
105*88459642SOmar Sandoval 			hint = 0;
106*88459642SOmar Sandoval 	}
107*88459642SOmar Sandoval 
108*88459642SOmar Sandoval 	return nr;
109*88459642SOmar Sandoval }
110*88459642SOmar Sandoval 
111*88459642SOmar Sandoval int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin)
112*88459642SOmar Sandoval {
113*88459642SOmar Sandoval 	unsigned int i, index;
114*88459642SOmar Sandoval 	int nr = -1;
115*88459642SOmar Sandoval 
116*88459642SOmar Sandoval 	index = SB_NR_TO_INDEX(sb, alloc_hint);
117*88459642SOmar Sandoval 
118*88459642SOmar Sandoval 	for (i = 0; i < sb->map_nr; i++) {
119*88459642SOmar Sandoval 		nr = __sbitmap_get_word(&sb->map[index],
120*88459642SOmar Sandoval 					SB_NR_TO_BIT(sb, alloc_hint),
121*88459642SOmar Sandoval 					!round_robin);
122*88459642SOmar Sandoval 		if (nr != -1) {
123*88459642SOmar Sandoval 			nr += index << sb->shift;
124*88459642SOmar Sandoval 			break;
125*88459642SOmar Sandoval 		}
126*88459642SOmar Sandoval 
127*88459642SOmar Sandoval 		/* Jump to next index. */
128*88459642SOmar Sandoval 		index++;
129*88459642SOmar Sandoval 		alloc_hint = index << sb->shift;
130*88459642SOmar Sandoval 
131*88459642SOmar Sandoval 		if (index >= sb->map_nr) {
132*88459642SOmar Sandoval 			index = 0;
133*88459642SOmar Sandoval 			alloc_hint = 0;
134*88459642SOmar Sandoval 		}
135*88459642SOmar Sandoval 	}
136*88459642SOmar Sandoval 
137*88459642SOmar Sandoval 	return nr;
138*88459642SOmar Sandoval }
139*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_get);
140*88459642SOmar Sandoval 
141*88459642SOmar Sandoval bool sbitmap_any_bit_set(const struct sbitmap *sb)
142*88459642SOmar Sandoval {
143*88459642SOmar Sandoval 	unsigned int i;
144*88459642SOmar Sandoval 
145*88459642SOmar Sandoval 	for (i = 0; i < sb->map_nr; i++) {
146*88459642SOmar Sandoval 		if (sb->map[i].word)
147*88459642SOmar Sandoval 			return true;
148*88459642SOmar Sandoval 	}
149*88459642SOmar Sandoval 	return false;
150*88459642SOmar Sandoval }
151*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_any_bit_set);
152*88459642SOmar Sandoval 
153*88459642SOmar Sandoval bool sbitmap_any_bit_clear(const struct sbitmap *sb)
154*88459642SOmar Sandoval {
155*88459642SOmar Sandoval 	unsigned int i;
156*88459642SOmar Sandoval 
157*88459642SOmar Sandoval 	for (i = 0; i < sb->map_nr; i++) {
158*88459642SOmar Sandoval 		const struct sbitmap_word *word = &sb->map[i];
159*88459642SOmar Sandoval 		unsigned long ret;
160*88459642SOmar Sandoval 
161*88459642SOmar Sandoval 		ret = find_first_zero_bit(&word->word, word->depth);
162*88459642SOmar Sandoval 		if (ret < word->depth)
163*88459642SOmar Sandoval 			return true;
164*88459642SOmar Sandoval 	}
165*88459642SOmar Sandoval 	return false;
166*88459642SOmar Sandoval }
167*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_any_bit_clear);
168*88459642SOmar Sandoval 
169*88459642SOmar Sandoval unsigned int sbitmap_weight(const struct sbitmap *sb)
170*88459642SOmar Sandoval {
171*88459642SOmar Sandoval 	unsigned int i, weight;
172*88459642SOmar Sandoval 
173*88459642SOmar Sandoval 	for (i = 0; i < sb->map_nr; i++) {
174*88459642SOmar Sandoval 		const struct sbitmap_word *word = &sb->map[i];
175*88459642SOmar Sandoval 
176*88459642SOmar Sandoval 		weight += bitmap_weight(&word->word, word->depth);
177*88459642SOmar Sandoval 	}
178*88459642SOmar Sandoval 	return weight;
179*88459642SOmar Sandoval }
180*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_weight);
181*88459642SOmar Sandoval 
182*88459642SOmar Sandoval static unsigned int sbq_calc_wake_batch(unsigned int depth)
183*88459642SOmar Sandoval {
184*88459642SOmar Sandoval 	unsigned int wake_batch;
185*88459642SOmar Sandoval 
186*88459642SOmar Sandoval 	/*
187*88459642SOmar Sandoval 	 * For each batch, we wake up one queue. We need to make sure that our
188*88459642SOmar Sandoval 	 * batch size is small enough that the full depth of the bitmap is
189*88459642SOmar Sandoval 	 * enough to wake up all of the queues.
190*88459642SOmar Sandoval 	 */
191*88459642SOmar Sandoval 	wake_batch = SBQ_WAKE_BATCH;
192*88459642SOmar Sandoval 	if (wake_batch > depth / SBQ_WAIT_QUEUES)
193*88459642SOmar Sandoval 		wake_batch = max(1U, depth / SBQ_WAIT_QUEUES);
194*88459642SOmar Sandoval 
195*88459642SOmar Sandoval 	return wake_batch;
196*88459642SOmar Sandoval }
197*88459642SOmar Sandoval 
198*88459642SOmar Sandoval int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth,
199*88459642SOmar Sandoval 			    int shift, gfp_t flags, int node)
200*88459642SOmar Sandoval {
201*88459642SOmar Sandoval 	int ret;
202*88459642SOmar Sandoval 	int i;
203*88459642SOmar Sandoval 
204*88459642SOmar Sandoval 	ret = sbitmap_init_node(&sbq->sb, depth, shift, flags, node);
205*88459642SOmar Sandoval 	if (ret)
206*88459642SOmar Sandoval 		return ret;
207*88459642SOmar Sandoval 
208*88459642SOmar Sandoval 	sbq->wake_batch = sbq_calc_wake_batch(depth);
209*88459642SOmar Sandoval 	atomic_set(&sbq->wake_index, 0);
210*88459642SOmar Sandoval 
211*88459642SOmar Sandoval 	sbq->ws = kzalloc(SBQ_WAIT_QUEUES * sizeof(*sbq->ws), flags);
212*88459642SOmar Sandoval 	if (!sbq->ws) {
213*88459642SOmar Sandoval 		sbitmap_free(&sbq->sb);
214*88459642SOmar Sandoval 		return -ENOMEM;
215*88459642SOmar Sandoval 	}
216*88459642SOmar Sandoval 
217*88459642SOmar Sandoval 	for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
218*88459642SOmar Sandoval 		init_waitqueue_head(&sbq->ws[i].wait);
219*88459642SOmar Sandoval 		atomic_set(&sbq->ws[i].wait_cnt, sbq->wake_batch);
220*88459642SOmar Sandoval 	}
221*88459642SOmar Sandoval 	return 0;
222*88459642SOmar Sandoval }
223*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_queue_init_node);
224*88459642SOmar Sandoval 
225*88459642SOmar Sandoval void sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth)
226*88459642SOmar Sandoval {
227*88459642SOmar Sandoval 	sbq->wake_batch = sbq_calc_wake_batch(depth);
228*88459642SOmar Sandoval 	sbitmap_resize(&sbq->sb, depth);
229*88459642SOmar Sandoval }
230*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_queue_resize);
231*88459642SOmar Sandoval 
232*88459642SOmar Sandoval static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq)
233*88459642SOmar Sandoval {
234*88459642SOmar Sandoval 	int i, wake_index;
235*88459642SOmar Sandoval 
236*88459642SOmar Sandoval 	wake_index = atomic_read(&sbq->wake_index);
237*88459642SOmar Sandoval 	for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
238*88459642SOmar Sandoval 		struct sbq_wait_state *ws = &sbq->ws[wake_index];
239*88459642SOmar Sandoval 
240*88459642SOmar Sandoval 		if (waitqueue_active(&ws->wait)) {
241*88459642SOmar Sandoval 			int o = atomic_read(&sbq->wake_index);
242*88459642SOmar Sandoval 
243*88459642SOmar Sandoval 			if (wake_index != o)
244*88459642SOmar Sandoval 				atomic_cmpxchg(&sbq->wake_index, o, wake_index);
245*88459642SOmar Sandoval 			return ws;
246*88459642SOmar Sandoval 		}
247*88459642SOmar Sandoval 
248*88459642SOmar Sandoval 		wake_index = sbq_index_inc(wake_index);
249*88459642SOmar Sandoval 	}
250*88459642SOmar Sandoval 
251*88459642SOmar Sandoval 	return NULL;
252*88459642SOmar Sandoval }
253*88459642SOmar Sandoval 
254*88459642SOmar Sandoval static void sbq_wake_up(struct sbitmap_queue *sbq)
255*88459642SOmar Sandoval {
256*88459642SOmar Sandoval 	struct sbq_wait_state *ws;
257*88459642SOmar Sandoval 	int wait_cnt;
258*88459642SOmar Sandoval 
259*88459642SOmar Sandoval 	/* Ensure that the wait list checks occur after clear_bit(). */
260*88459642SOmar Sandoval 	smp_mb();
261*88459642SOmar Sandoval 
262*88459642SOmar Sandoval 	ws = sbq_wake_ptr(sbq);
263*88459642SOmar Sandoval 	if (!ws)
264*88459642SOmar Sandoval 		return;
265*88459642SOmar Sandoval 
266*88459642SOmar Sandoval 	wait_cnt = atomic_dec_return(&ws->wait_cnt);
267*88459642SOmar Sandoval 	if (unlikely(wait_cnt < 0))
268*88459642SOmar Sandoval 		wait_cnt = atomic_inc_return(&ws->wait_cnt);
269*88459642SOmar Sandoval 	if (wait_cnt == 0) {
270*88459642SOmar Sandoval 		atomic_add(sbq->wake_batch, &ws->wait_cnt);
271*88459642SOmar Sandoval 		sbq_index_atomic_inc(&sbq->wake_index);
272*88459642SOmar Sandoval 		wake_up(&ws->wait);
273*88459642SOmar Sandoval 	}
274*88459642SOmar Sandoval }
275*88459642SOmar Sandoval 
276*88459642SOmar Sandoval void sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr)
277*88459642SOmar Sandoval {
278*88459642SOmar Sandoval 	sbitmap_clear_bit(&sbq->sb, nr);
279*88459642SOmar Sandoval 	sbq_wake_up(sbq);
280*88459642SOmar Sandoval }
281*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_queue_clear);
282*88459642SOmar Sandoval 
283*88459642SOmar Sandoval void sbitmap_queue_wake_all(struct sbitmap_queue *sbq)
284*88459642SOmar Sandoval {
285*88459642SOmar Sandoval 	int i, wake_index;
286*88459642SOmar Sandoval 
287*88459642SOmar Sandoval 	/*
288*88459642SOmar Sandoval 	 * Make sure all changes prior to this are visible from other CPUs.
289*88459642SOmar Sandoval 	 */
290*88459642SOmar Sandoval 	smp_mb();
291*88459642SOmar Sandoval 	wake_index = atomic_read(&sbq->wake_index);
292*88459642SOmar Sandoval 	for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
293*88459642SOmar Sandoval 		struct sbq_wait_state *ws = &sbq->ws[wake_index];
294*88459642SOmar Sandoval 
295*88459642SOmar Sandoval 		if (waitqueue_active(&ws->wait))
296*88459642SOmar Sandoval 			wake_up(&ws->wait);
297*88459642SOmar Sandoval 
298*88459642SOmar Sandoval 		wake_index = sbq_index_inc(wake_index);
299*88459642SOmar Sandoval 	}
300*88459642SOmar Sandoval }
301*88459642SOmar Sandoval EXPORT_SYMBOL_GPL(sbitmap_queue_wake_all);
302