1 /*
2  * RCU node combining tree definitions.  These are used to compute
3  * global attributes while avoiding common-case global contention.  A key
4  * property that these computations rely on is a tournament-style approach
5  * where only one of the tasks contending a lower level in the tree need
6  * advance to the next higher level.  If properly configured, this allows
7  * unlimited scalability while maintaining a constant level of contention
8  * on the root node.
9  *
10  * This seemingly RCU-private file must be available to SRCU users
11  * because the size of the TREE SRCU srcu_struct structure depends
12  * on these definitions.
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, you can access it online at
26  * http://www.gnu.org/licenses/gpl-2.0.html.
27  *
28  * Copyright IBM Corporation, 2017
29  *
30  * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
31  */
32 
33 #ifndef __LINUX_RCU_NODE_TREE_H
34 #define __LINUX_RCU_NODE_TREE_H
35 
36 /*
37  * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and
38  * CONFIG_RCU_FANOUT_LEAF.
39  * In theory, it should be possible to add more levels straightforwardly.
40  * In practice, this did work well going from three levels to four.
41  * Of course, your mileage may vary.
42  */
43 
44 #ifdef CONFIG_RCU_FANOUT
45 #define RCU_FANOUT CONFIG_RCU_FANOUT
46 #else /* #ifdef CONFIG_RCU_FANOUT */
47 # ifdef CONFIG_64BIT
48 # define RCU_FANOUT 64
49 # else
50 # define RCU_FANOUT 32
51 # endif
52 #endif /* #else #ifdef CONFIG_RCU_FANOUT */
53 
54 #ifdef CONFIG_RCU_FANOUT_LEAF
55 #define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF
56 #else /* #ifdef CONFIG_RCU_FANOUT_LEAF */
57 #define RCU_FANOUT_LEAF 16
58 #endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */
59 
60 #define RCU_FANOUT_1	      (RCU_FANOUT_LEAF)
61 #define RCU_FANOUT_2	      (RCU_FANOUT_1 * RCU_FANOUT)
62 #define RCU_FANOUT_3	      (RCU_FANOUT_2 * RCU_FANOUT)
63 #define RCU_FANOUT_4	      (RCU_FANOUT_3 * RCU_FANOUT)
64 
65 #if NR_CPUS <= RCU_FANOUT_1
66 #  define RCU_NUM_LVLS	      1
67 #  define NUM_RCU_LVL_0	      1
68 #  define NUM_RCU_NODES	      NUM_RCU_LVL_0
69 #  define NUM_RCU_LVL_INIT    { NUM_RCU_LVL_0 }
70 #  define RCU_NODE_NAME_INIT  { "rcu_node_0" }
71 #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0" }
72 #elif NR_CPUS <= RCU_FANOUT_2
73 #  define RCU_NUM_LVLS	      2
74 #  define NUM_RCU_LVL_0	      1
75 #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)
76 #  define NUM_RCU_NODES	      (NUM_RCU_LVL_0 + NUM_RCU_LVL_1)
77 #  define NUM_RCU_LVL_INIT    { NUM_RCU_LVL_0, NUM_RCU_LVL_1 }
78 #  define RCU_NODE_NAME_INIT  { "rcu_node_0", "rcu_node_1" }
79 #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0", "rcu_node_fqs_1" }
80 #elif NR_CPUS <= RCU_FANOUT_3
81 #  define RCU_NUM_LVLS	      3
82 #  define NUM_RCU_LVL_0	      1
83 #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)
84 #  define NUM_RCU_LVL_2	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)
85 #  define NUM_RCU_NODES	      (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2)
86 #  define NUM_RCU_LVL_INIT    { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 }
87 #  define RCU_NODE_NAME_INIT  { "rcu_node_0", "rcu_node_1", "rcu_node_2" }
88 #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" }
89 #elif NR_CPUS <= RCU_FANOUT_4
90 #  define RCU_NUM_LVLS	      4
91 #  define NUM_RCU_LVL_0	      1
92 #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3)
93 #  define NUM_RCU_LVL_2	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)
94 #  define NUM_RCU_LVL_3	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)
95 #  define NUM_RCU_NODES	      (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3)
96 #  define NUM_RCU_LVL_INIT    { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 }
97 #  define RCU_NODE_NAME_INIT  { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" }
98 #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" }
99 #else
100 # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
101 #endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
102 
103 #endif /* __LINUX_RCU_NODE_TREE_H */
104