linux/arch/s390/numa/toptree.c
<<
>>
Prefs
   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}
 343