Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * NUMA support for s390
  3 *
  4 * A tree structure used for machine topology mangling
  5 *
  6 * Copyright IBM Corp. 2015
  7 */
  8
  9#include <linux/kernel.h>
 10#include <linux/cpumask.h>
 11#include <linux/list.h>
 12#include <linux/list_sort.h>
 13#include <linux/slab.h>
 14#include <asm/numa.h>
 15
 16#include "toptree.h"
 17
 18/**
 19 * toptree_alloc - Allocate and initialize a new tree node.
 20 * @level: The node's vertical level; level 0 contains the leaves.
 21 * @id: ID number, explicitly not unique beyond scope of node's siblings
 22 *
 23 * Allocate a new tree node and initialize it.
 24 *
 25 * RETURNS:
 26 * Pointer to the new tree node or NULL on error
 27 */
 28struct toptree *toptree_alloc(int level, int id)
 29{
 30	struct toptree *res = kzalloc(sizeof(struct toptree), GFP_KERNEL);
 31
 32	if (!res)
 33		return res;
 34
 35	INIT_LIST_HEAD(&res->children);
 36	INIT_LIST_HEAD(&res->sibling);
 37	cpumask_clear(&res->mask);
 38	res->level = level;
 39	res->id = id;
 40	return res;
 41}
 42
 43/**
 44 * toptree_remove - Remove a tree node from a tree
 45 * @cand: Pointer to the node to remove
 46 *
 47 * The node is detached from its parent node. The parent node's
 48 * masks will be updated to reflect the loss of the child.
 49 */
 50static void toptree_remove(struct toptree *cand)
 51{
 52	struct toptree *oldparent;
 53
 54	list_del_init(&cand->sibling);
 55	oldparent = cand->parent;
 56	cand->parent = NULL;
 57	toptree_update_mask(oldparent);
 58}
 59
 60/**
 61 * toptree_free - discard a tree node
 62 * @cand: Pointer to the tree node to discard
 63 *
 64 * Checks if @cand is attached to a parent node. Detaches it
 65 * cleanly using toptree_remove. Possible children are freed
 66 * recursively. In the end @cand itself is freed.
 67 */
 68void toptree_free(struct toptree *cand)
 69{
 70	struct toptree *child, *tmp;
 71
 72	if (cand->parent)
 73		toptree_remove(cand);
 74	toptree_for_each_child_safe(child, tmp, cand)
 75		toptree_free(child);
 76	kfree(cand);
 77}
 78
 79/**
 80 * toptree_update_mask - Update node bitmasks
 81 * @cand: Pointer to a tree node
 82 *
 83 * The node's cpumask will be updated by combining all children's
 84 * masks. Then toptree_update_mask is called recursively for the
 85 * parent if applicable.
 86 *
 87 * NOTE:
 88 * This must not be called on leaves. If called on a leaf, its
 89 * CPU mask is cleared and lost.
 90 */
 91void toptree_update_mask(struct toptree *cand)
 92{
 93	struct toptree *child;
 94
 95	cpumask_clear(&cand->mask);
 96	list_for_each_entry(child, &cand->children, sibling)
 97		cpumask_or(&cand->mask, &cand->mask, &child->mask);
 98	if (cand->parent)
 99		toptree_update_mask(cand->parent);
100}
101
102/**
103 * toptree_insert - Insert a tree node into tree
104 * @cand: Pointer to the node to insert
105 * @target: Pointer to the node to which @cand will added as a child
106 *
107 * Insert a tree node into a tree. Masks will be updated automatically.
108 *
109 * RETURNS:
110 * 0 on success, -1 if NULL is passed as argument or the node levels
111 * don't fit.
112 */
113static int toptree_insert(struct toptree *cand, struct toptree *target)
114{
115	if (!cand || !target)
116		return -1;
117	if (target->level != (cand->level + 1))
118		return -1;
119	list_add_tail(&cand->sibling, &target->children);
120	cand->parent = target;
121	toptree_update_mask(target);
122	return 0;
123}
124
125/**
126 * toptree_move_children - Move all child nodes of a node to a new place
127 * @cand: Pointer to the node whose children are to be moved
128 * @target: Pointer to the node to which @cand's children will be attached
129 *
130 * Take all child nodes of @cand and move them using toptree_move.
131 */
132static void toptree_move_children(struct toptree *cand, struct toptree *target)
133{
134	struct toptree *child, *tmp;
135
136	toptree_for_each_child_safe(child, tmp, cand)
137		toptree_move(child, target);
138}
139
140/**
141 * toptree_unify - Merge children with same ID
142 * @cand: Pointer to node whose direct children should be made unique
143 *
144 * When mangling the tree it is possible that a node has two or more children
145 * which have the same ID. This routine merges these children into one and
146 * moves all children of the merged nodes into the unified node.
147 */
148void toptree_unify(struct toptree *cand)
149{
150	struct toptree *child, *tmp, *cand_copy;
151
152	/* Threads cannot be split, cores are not split */
153	if (cand->level < 2)
154		return;
155
156	cand_copy = toptree_alloc(cand->level, 0);
157	toptree_for_each_child_safe(child, tmp, cand) {
158		struct toptree *tmpchild;
159
160		if (!cpumask_empty(&child->mask)) {
161			tmpchild = toptree_get_child(cand_copy, child->id);
162			toptree_move_children(child, tmpchild);
163		}
164		toptree_free(child);
165	}
166	toptree_move_children(cand_copy, cand);
167	toptree_free(cand_copy);
168
169	toptree_for_each_child(child, cand)
170		toptree_unify(child);
171}
172
173/**
174 * toptree_move - Move a node to another context
175 * @cand: Pointer to the node to move
176 * @target: Pointer to the node where @cand should go
177 *
178 * In the easiest case @cand is exactly on the level below @target
179 * and will be immediately moved to the target.
180 *
181 * If @target's level is not the direct parent level of @cand,
182 * nodes for the missing levels are created and put between
183 * @cand and @target. The "stacking" nodes' IDs are taken from
184 * @cand's parents.
185 *
186 * After this it is likely to have redundant nodes in the tree
187 * which are addressed by means of toptree_unify.
188 */
189void toptree_move(struct toptree *cand, struct toptree *target)
190{
191	struct toptree *stack_target, *real_insert_point, *ptr, *tmp;
192
193	if (cand->level + 1 == target->level) {
194		toptree_remove(cand);
195		toptree_insert(cand, target);
196		return;
197	}
198
199	real_insert_point = NULL;
200	ptr = cand;
201	stack_target = NULL;
202
203	do {
204		tmp = stack_target;
205		stack_target = toptree_alloc(ptr->level + 1,
206					     ptr->parent->id);
207		toptree_insert(tmp, stack_target);
208		if (!real_insert_point)
209			real_insert_point = stack_target;
210		ptr = ptr->parent;
211	} while (stack_target->level < (target->level - 1));
212
213	toptree_remove(cand);
214	toptree_insert(cand, real_insert_point);
215	toptree_insert(stack_target, target);
216}
217
218/**
219 * toptree_get_child - Access a tree node's child by its ID
220 * @cand: Pointer to tree node whose child is to access
221 * @id: The desired child's ID
222 *
223 * @cand's children are searched for a child with matching ID.
224 * If no match can be found, a new child with the desired ID
225 * is created and returned.
226 */
227struct toptree *toptree_get_child(struct toptree *cand, int id)
228{
229	struct toptree *child;
230
231	toptree_for_each_child(child, cand)
232		if (child->id == id)
233			return child;
234	child = toptree_alloc(cand->level-1, id);
235	toptree_insert(child, cand);
236	return child;
237}
238
239/**
240 * toptree_first - Find the first descendant on specified level
241 * @context: Pointer to tree node whose descendants are to be used
242 * @level: The level of interest
243 *
244 * RETURNS:
245 * @context's first descendant on the specified level, or NULL
246 * if there is no matching descendant
247 */
248struct toptree *toptree_first(struct toptree *context, int level)
249{
250	struct toptree *child, *tmp;
251
252	if (context->level == level)
253		return context;
254
255	if (!list_empty(&context->children)) {
256		list_for_each_entry(child, &context->children, sibling) {
257			tmp = toptree_first(child, level);
258			if (tmp)
259				return tmp;
260		}
261	}
262	return NULL;
263}
264
265/**
266 * toptree_next_sibling - Return next sibling
267 * @cur: Pointer to a tree node
268 *
269 * RETURNS:
270 * If @cur has a parent and is not the last in the parent's children list,
271 * the next sibling is returned. Or NULL when there are no siblings left.
272 */
273static struct toptree *toptree_next_sibling(struct toptree *cur)
274{
275	if (cur->parent == NULL)
276		return NULL;
277
278	if (cur == list_last_entry(&cur->parent->children,
279				   struct toptree, sibling))
280		return NULL;
281	return (struct toptree *) list_next_entry(cur, sibling);
282}
283
284/**
285 * toptree_next - Tree traversal function
286 * @cur: Pointer to current element
287 * @context: Pointer to the root node of the tree or subtree to
288 * be traversed.
289 * @level: The level of interest.
290 *
291 * RETURNS:
292 * Pointer to the next node on level @level
293 * or NULL when there is no next node.
294 */
295struct toptree *toptree_next(struct toptree *cur, struct toptree *context,
296			     int level)
297{
298	struct toptree *cur_context, *tmp;
299
300	if (!cur)
301		return NULL;
302
303	if (context->level == level)
304		return NULL;
305
306	tmp = toptree_next_sibling(cur);
307	if (tmp != NULL)
308		return tmp;
309
310	cur_context = cur;
311	while (cur_context->level < context->level - 1) {
312		/* Step up */
313		cur_context = cur_context->parent;
314		/* Step aside */
315		tmp = toptree_next_sibling(cur_context);
316		if (tmp != NULL) {
317			/* Step down */
318			tmp = toptree_first(tmp, level);
319			if (tmp != NULL)
320				return tmp;
321		}
322	}
323	return NULL;
324}
325
326/**
327 * toptree_count - Count descendants on specified level
328 * @context: Pointer to node whose descendants are to be considered
329 * @level: Only descendants on the specified level will be counted
330 *
331 * RETURNS:
332 * Number of descendants on the specified level
333 */
334int toptree_count(struct toptree *context, int level)
335{
336	struct toptree *cur;
337	int cnt = 0;
338
339	toptree_for_each(cur, context, level)
340		cnt++;
341	return cnt;
342}