xref: /openbmc/linux/arch/sparc/kernel/cpumap.c (revision 60da7d0b)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2280ff974SHong H. Pham /* cpumap.c: used for optimizing CPU assignment
3280ff974SHong H. Pham  *
4280ff974SHong H. Pham  * Copyright (C) 2009 Hong H. Pham <hong.pham@windriver.com>
5280ff974SHong H. Pham  */
6280ff974SHong H. Pham 
7066bcacaSPaul Gortmaker #include <linux/export.h>
85a0e3ad6STejun Heo #include <linux/slab.h>
9280ff974SHong H. Pham #include <linux/kernel.h>
10280ff974SHong H. Pham #include <linux/cpumask.h>
11280ff974SHong H. Pham #include <linux/spinlock.h>
12280ff974SHong H. Pham #include <asm/cpudata.h>
13280ff974SHong H. Pham #include "cpumap.h"
14280ff974SHong H. Pham 
15280ff974SHong H. Pham 
16280ff974SHong H. Pham enum {
17280ff974SHong H. Pham 	CPUINFO_LVL_ROOT = 0,
18280ff974SHong H. Pham 	CPUINFO_LVL_NODE,
19280ff974SHong H. Pham 	CPUINFO_LVL_CORE,
20280ff974SHong H. Pham 	CPUINFO_LVL_PROC,
21280ff974SHong H. Pham 	CPUINFO_LVL_MAX,
22280ff974SHong H. Pham };
23280ff974SHong H. Pham 
24280ff974SHong H. Pham enum {
25280ff974SHong H. Pham 	ROVER_NO_OP              = 0,
26280ff974SHong H. Pham 	/* Increment rover every time level is visited */
27280ff974SHong H. Pham 	ROVER_INC_ON_VISIT       = 1 << 0,
28280ff974SHong H. Pham 	/* Increment parent's rover every time rover wraps around */
29280ff974SHong H. Pham 	ROVER_INC_PARENT_ON_LOOP = 1 << 1,
30280ff974SHong H. Pham };
31280ff974SHong H. Pham 
32280ff974SHong H. Pham struct cpuinfo_node {
33280ff974SHong H. Pham 	int id;
34280ff974SHong H. Pham 	int level;
35280ff974SHong H. Pham 	int num_cpus;    /* Number of CPUs in this hierarchy */
36280ff974SHong H. Pham 	int parent_index;
37280ff974SHong H. Pham 	int child_start; /* Array index of the first child node */
38280ff974SHong H. Pham 	int child_end;   /* Array index of the last child node */
39280ff974SHong H. Pham 	int rover;       /* Child node iterator */
40280ff974SHong H. Pham };
41280ff974SHong H. Pham 
42280ff974SHong H. Pham struct cpuinfo_level {
43280ff974SHong H. Pham 	int start_index; /* Index of first node of a level in a cpuinfo tree */
44280ff974SHong H. Pham 	int end_index;   /* Index of last node of a level in a cpuinfo tree */
45280ff974SHong H. Pham 	int num_nodes;   /* Number of nodes in a level in a cpuinfo tree */
46280ff974SHong H. Pham };
47280ff974SHong H. Pham 
48280ff974SHong H. Pham struct cpuinfo_tree {
49280ff974SHong H. Pham 	int total_nodes;
50280ff974SHong H. Pham 
51280ff974SHong H. Pham 	/* Offsets into nodes[] for each level of the tree */
52280ff974SHong H. Pham 	struct cpuinfo_level level[CPUINFO_LVL_MAX];
5360da7d0bSGustavo A. R. Silva 	struct cpuinfo_node  nodes[];
54280ff974SHong H. Pham };
55280ff974SHong H. Pham 
56280ff974SHong H. Pham 
57280ff974SHong H. Pham static struct cpuinfo_tree *cpuinfo_tree;
58280ff974SHong H. Pham 
59280ff974SHong H. Pham static u16 cpu_distribution_map[NR_CPUS];
60280ff974SHong H. Pham static DEFINE_SPINLOCK(cpu_map_lock);
61280ff974SHong H. Pham 
62280ff974SHong H. Pham 
63280ff974SHong H. Pham /* Niagara optimized cpuinfo tree traversal. */
64280ff974SHong H. Pham static const int niagara_iterate_method[] = {
65280ff974SHong H. Pham 	[CPUINFO_LVL_ROOT] = ROVER_NO_OP,
66280ff974SHong H. Pham 
67280ff974SHong H. Pham 	/* Strands (or virtual CPUs) within a core may not run concurrently
68280ff974SHong H. Pham 	 * on the Niagara, as instruction pipeline(s) are shared.  Distribute
69280ff974SHong H. Pham 	 * work to strands in different cores first for better concurrency.
70280ff974SHong H. Pham 	 * Go to next NUMA node when all cores are used.
71280ff974SHong H. Pham 	 */
72280ff974SHong H. Pham 	[CPUINFO_LVL_NODE] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP,
73280ff974SHong H. Pham 
74280ff974SHong H. Pham 	/* Strands are grouped together by proc_id in cpuinfo_sparc, i.e.
75280ff974SHong H. Pham 	 * a proc_id represents an instruction pipeline.  Distribute work to
76280ff974SHong H. Pham 	 * strands in different proc_id groups if the core has multiple
77280ff974SHong H. Pham 	 * instruction pipelines (e.g. the Niagara 2/2+ has two).
78280ff974SHong H. Pham 	 */
79280ff974SHong H. Pham 	[CPUINFO_LVL_CORE] = ROVER_INC_ON_VISIT,
80280ff974SHong H. Pham 
81280ff974SHong H. Pham 	/* Pick the next strand in the proc_id group. */
82280ff974SHong H. Pham 	[CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT,
83280ff974SHong H. Pham };
84280ff974SHong H. Pham 
85280ff974SHong H. Pham /* Generic cpuinfo tree traversal.  Distribute work round robin across NUMA
86280ff974SHong H. Pham  * nodes.
87280ff974SHong H. Pham  */
88280ff974SHong H. Pham static const int generic_iterate_method[] = {
89280ff974SHong H. Pham 	[CPUINFO_LVL_ROOT] = ROVER_INC_ON_VISIT,
90280ff974SHong H. Pham 	[CPUINFO_LVL_NODE] = ROVER_NO_OP,
91280ff974SHong H. Pham 	[CPUINFO_LVL_CORE] = ROVER_INC_PARENT_ON_LOOP,
92280ff974SHong H. Pham 	[CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP,
93280ff974SHong H. Pham };
94280ff974SHong H. Pham 
95280ff974SHong H. Pham 
cpuinfo_id(int cpu,int level)96280ff974SHong H. Pham static int cpuinfo_id(int cpu, int level)
97280ff974SHong H. Pham {
98280ff974SHong H. Pham 	int id;
99280ff974SHong H. Pham 
100280ff974SHong H. Pham 	switch (level) {
101280ff974SHong H. Pham 	case CPUINFO_LVL_ROOT:
102280ff974SHong H. Pham 		id = 0;
103280ff974SHong H. Pham 		break;
104280ff974SHong H. Pham 	case CPUINFO_LVL_NODE:
105280ff974SHong H. Pham 		id = cpu_to_node(cpu);
106280ff974SHong H. Pham 		break;
107280ff974SHong H. Pham 	case CPUINFO_LVL_CORE:
108280ff974SHong H. Pham 		id = cpu_data(cpu).core_id;
109280ff974SHong H. Pham 		break;
110280ff974SHong H. Pham 	case CPUINFO_LVL_PROC:
111280ff974SHong H. Pham 		id = cpu_data(cpu).proc_id;
112280ff974SHong H. Pham 		break;
113280ff974SHong H. Pham 	default:
114280ff974SHong H. Pham 		id = -EINVAL;
115280ff974SHong H. Pham 	}
116280ff974SHong H. Pham 	return id;
117280ff974SHong H. Pham }
118280ff974SHong H. Pham 
119280ff974SHong H. Pham /*
120280ff974SHong H. Pham  * Enumerate the CPU information in __cpu_data to determine the start index,
121280ff974SHong H. Pham  * end index, and number of nodes for each level in the cpuinfo tree.  The
122280ff974SHong H. Pham  * total number of cpuinfo nodes required to build the tree is returned.
123280ff974SHong H. Pham  */
enumerate_cpuinfo_nodes(struct cpuinfo_level * tree_level)124280ff974SHong H. Pham static int enumerate_cpuinfo_nodes(struct cpuinfo_level *tree_level)
125280ff974SHong H. Pham {
126280ff974SHong H. Pham 	int prev_id[CPUINFO_LVL_MAX];
127280ff974SHong H. Pham 	int i, n, num_nodes;
128280ff974SHong H. Pham 
129280ff974SHong H. Pham 	for (i = CPUINFO_LVL_ROOT; i < CPUINFO_LVL_MAX; i++) {
130280ff974SHong H. Pham 		struct cpuinfo_level *lv = &tree_level[i];
131280ff974SHong H. Pham 
132280ff974SHong H. Pham 		prev_id[i] = -1;
133280ff974SHong H. Pham 		lv->start_index = lv->end_index = lv->num_nodes = 0;
134280ff974SHong H. Pham 	}
135280ff974SHong H. Pham 
136280ff974SHong H. Pham 	num_nodes = 1; /* Include the root node */
137280ff974SHong H. Pham 
138280ff974SHong H. Pham 	for (i = 0; i < num_possible_cpus(); i++) {
139280ff974SHong H. Pham 		if (!cpu_online(i))
140280ff974SHong H. Pham 			continue;
141280ff974SHong H. Pham 
142280ff974SHong H. Pham 		n = cpuinfo_id(i, CPUINFO_LVL_NODE);
143280ff974SHong H. Pham 		if (n > prev_id[CPUINFO_LVL_NODE]) {
144280ff974SHong H. Pham 			tree_level[CPUINFO_LVL_NODE].num_nodes++;
145280ff974SHong H. Pham 			prev_id[CPUINFO_LVL_NODE] = n;
146280ff974SHong H. Pham 			num_nodes++;
147280ff974SHong H. Pham 		}
148280ff974SHong H. Pham 		n = cpuinfo_id(i, CPUINFO_LVL_CORE);
149280ff974SHong H. Pham 		if (n > prev_id[CPUINFO_LVL_CORE]) {
150280ff974SHong H. Pham 			tree_level[CPUINFO_LVL_CORE].num_nodes++;
151280ff974SHong H. Pham 			prev_id[CPUINFO_LVL_CORE] = n;
152280ff974SHong H. Pham 			num_nodes++;
153280ff974SHong H. Pham 		}
154280ff974SHong H. Pham 		n = cpuinfo_id(i, CPUINFO_LVL_PROC);
155280ff974SHong H. Pham 		if (n > prev_id[CPUINFO_LVL_PROC]) {
156280ff974SHong H. Pham 			tree_level[CPUINFO_LVL_PROC].num_nodes++;
157280ff974SHong H. Pham 			prev_id[CPUINFO_LVL_PROC] = n;
158280ff974SHong H. Pham 			num_nodes++;
159280ff974SHong H. Pham 		}
160280ff974SHong H. Pham 	}
161280ff974SHong H. Pham 
162280ff974SHong H. Pham 	tree_level[CPUINFO_LVL_ROOT].num_nodes = 1;
163280ff974SHong H. Pham 
164280ff974SHong H. Pham 	n = tree_level[CPUINFO_LVL_NODE].num_nodes;
165280ff974SHong H. Pham 	tree_level[CPUINFO_LVL_NODE].start_index = 1;
166280ff974SHong H. Pham 	tree_level[CPUINFO_LVL_NODE].end_index   = n;
167280ff974SHong H. Pham 
168280ff974SHong H. Pham 	n++;
169280ff974SHong H. Pham 	tree_level[CPUINFO_LVL_CORE].start_index = n;
170280ff974SHong H. Pham 	n += tree_level[CPUINFO_LVL_CORE].num_nodes;
171280ff974SHong H. Pham 	tree_level[CPUINFO_LVL_CORE].end_index   = n - 1;
172280ff974SHong H. Pham 
173280ff974SHong H. Pham 	tree_level[CPUINFO_LVL_PROC].start_index = n;
174280ff974SHong H. Pham 	n += tree_level[CPUINFO_LVL_PROC].num_nodes;
175280ff974SHong H. Pham 	tree_level[CPUINFO_LVL_PROC].end_index   = n - 1;
176280ff974SHong H. Pham 
177280ff974SHong H. Pham 	return num_nodes;
178280ff974SHong H. Pham }
179280ff974SHong H. Pham 
180280ff974SHong H. Pham /* Build a tree representation of the CPU hierarchy using the per CPU
181280ff974SHong H. Pham  * information in __cpu_data.  Entries in __cpu_data[0..NR_CPUS] are
182280ff974SHong H. Pham  * assumed to be sorted in ascending order based on node, core_id, and
183280ff974SHong H. Pham  * proc_id (in order of significance).
184280ff974SHong H. Pham  */
build_cpuinfo_tree(void)185280ff974SHong H. Pham static struct cpuinfo_tree *build_cpuinfo_tree(void)
186280ff974SHong H. Pham {
187280ff974SHong H. Pham 	struct cpuinfo_tree *new_tree;
188280ff974SHong H. Pham 	struct cpuinfo_node *node;
189280ff974SHong H. Pham 	struct cpuinfo_level tmp_level[CPUINFO_LVL_MAX];
190280ff974SHong H. Pham 	int num_cpus[CPUINFO_LVL_MAX];
191280ff974SHong H. Pham 	int level_rover[CPUINFO_LVL_MAX];
192280ff974SHong H. Pham 	int prev_id[CPUINFO_LVL_MAX];
193280ff974SHong H. Pham 	int n, id, cpu, prev_cpu, last_cpu, level;
194280ff974SHong H. Pham 
195280ff974SHong H. Pham 	n = enumerate_cpuinfo_nodes(tmp_level);
196280ff974SHong H. Pham 
197bc0025b6SGustavo A. R. Silva 	new_tree = kzalloc(struct_size(new_tree, nodes, n), GFP_ATOMIC);
198280ff974SHong H. Pham 	if (!new_tree)
199280ff974SHong H. Pham 		return NULL;
200280ff974SHong H. Pham 
201280ff974SHong H. Pham 	new_tree->total_nodes = n;
202280ff974SHong H. Pham 	memcpy(&new_tree->level, tmp_level, sizeof(tmp_level));
203280ff974SHong H. Pham 
204fb1fece5SKOSAKI Motohiro 	prev_cpu = cpu = cpumask_first(cpu_online_mask);
205280ff974SHong H. Pham 
206280ff974SHong H. Pham 	/* Initialize all levels in the tree with the first CPU */
207280ff974SHong H. Pham 	for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; level--) {
208280ff974SHong H. Pham 		n = new_tree->level[level].start_index;
209280ff974SHong H. Pham 
210280ff974SHong H. Pham 		level_rover[level] = n;
211280ff974SHong H. Pham 		node = &new_tree->nodes[n];
212280ff974SHong H. Pham 
213280ff974SHong H. Pham 		id = cpuinfo_id(cpu, level);
214280ff974SHong H. Pham 		if (unlikely(id < 0)) {
215280ff974SHong H. Pham 			kfree(new_tree);
216280ff974SHong H. Pham 			return NULL;
217280ff974SHong H. Pham 		}
218280ff974SHong H. Pham 		node->id = id;
219280ff974SHong H. Pham 		node->level = level;
220280ff974SHong H. Pham 		node->num_cpus = 1;
221280ff974SHong H. Pham 
222280ff974SHong H. Pham 		node->parent_index = (level > CPUINFO_LVL_ROOT)
223280ff974SHong H. Pham 		    ? new_tree->level[level - 1].start_index : -1;
224280ff974SHong H. Pham 
225280ff974SHong H. Pham 		node->child_start = node->child_end = node->rover =
226280ff974SHong H. Pham 		    (level == CPUINFO_LVL_PROC)
227280ff974SHong H. Pham 		    ? cpu : new_tree->level[level + 1].start_index;
228280ff974SHong H. Pham 
229280ff974SHong H. Pham 		prev_id[level] = node->id;
230280ff974SHong H. Pham 		num_cpus[level] = 1;
231280ff974SHong H. Pham 	}
232280ff974SHong H. Pham 
233280ff974SHong H. Pham 	for (last_cpu = (num_possible_cpus() - 1); last_cpu >= 0; last_cpu--) {
234280ff974SHong H. Pham 		if (cpu_online(last_cpu))
235280ff974SHong H. Pham 			break;
236280ff974SHong H. Pham 	}
237280ff974SHong H. Pham 
238280ff974SHong H. Pham 	while (++cpu <= last_cpu) {
239280ff974SHong H. Pham 		if (!cpu_online(cpu))
240280ff974SHong H. Pham 			continue;
241280ff974SHong H. Pham 
242280ff974SHong H. Pham 		for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT;
243280ff974SHong H. Pham 		     level--) {
244280ff974SHong H. Pham 			id = cpuinfo_id(cpu, level);
245280ff974SHong H. Pham 			if (unlikely(id < 0)) {
246280ff974SHong H. Pham 				kfree(new_tree);
247280ff974SHong H. Pham 				return NULL;
248280ff974SHong H. Pham 			}
249280ff974SHong H. Pham 
250280ff974SHong H. Pham 			if ((id != prev_id[level]) || (cpu == last_cpu)) {
251280ff974SHong H. Pham 				prev_id[level] = id;
252280ff974SHong H. Pham 				node = &new_tree->nodes[level_rover[level]];
253280ff974SHong H. Pham 				node->num_cpus = num_cpus[level];
254280ff974SHong H. Pham 				num_cpus[level] = 1;
255280ff974SHong H. Pham 
256280ff974SHong H. Pham 				if (cpu == last_cpu)
257280ff974SHong H. Pham 					node->num_cpus++;
258280ff974SHong H. Pham 
259280ff974SHong H. Pham 				/* Connect tree node to parent */
260280ff974SHong H. Pham 				if (level == CPUINFO_LVL_ROOT)
261280ff974SHong H. Pham 					node->parent_index = -1;
262280ff974SHong H. Pham 				else
263280ff974SHong H. Pham 					node->parent_index =
264280ff974SHong H. Pham 					    level_rover[level - 1];
265280ff974SHong H. Pham 
266280ff974SHong H. Pham 				if (level == CPUINFO_LVL_PROC) {
267280ff974SHong H. Pham 					node->child_end =
268280ff974SHong H. Pham 					    (cpu == last_cpu) ? cpu : prev_cpu;
269280ff974SHong H. Pham 				} else {
270280ff974SHong H. Pham 					node->child_end =
271280ff974SHong H. Pham 					    level_rover[level + 1] - 1;
272280ff974SHong H. Pham 				}
273280ff974SHong H. Pham 
274280ff974SHong H. Pham 				/* Initialize the next node in the same level */
275280ff974SHong H. Pham 				n = ++level_rover[level];
276280ff974SHong H. Pham 				if (n <= new_tree->level[level].end_index) {
277280ff974SHong H. Pham 					node = &new_tree->nodes[n];
278280ff974SHong H. Pham 					node->id = id;
279280ff974SHong H. Pham 					node->level = level;
280280ff974SHong H. Pham 
281280ff974SHong H. Pham 					/* Connect node to child */
282280ff974SHong H. Pham 					node->child_start = node->child_end =
283280ff974SHong H. Pham 					node->rover =
284280ff974SHong H. Pham 					    (level == CPUINFO_LVL_PROC)
285280ff974SHong H. Pham 					    ? cpu : level_rover[level + 1];
286280ff974SHong H. Pham 				}
287280ff974SHong H. Pham 			} else
288280ff974SHong H. Pham 				num_cpus[level]++;
289280ff974SHong H. Pham 		}
290280ff974SHong H. Pham 		prev_cpu = cpu;
291280ff974SHong H. Pham 	}
292280ff974SHong H. Pham 
293280ff974SHong H. Pham 	return new_tree;
294280ff974SHong H. Pham }
295280ff974SHong H. Pham 
increment_rover(struct cpuinfo_tree * t,int node_index,int root_index,const int * rover_inc_table)296280ff974SHong H. Pham static void increment_rover(struct cpuinfo_tree *t, int node_index,
297280ff974SHong H. Pham                             int root_index, const int *rover_inc_table)
298280ff974SHong H. Pham {
299280ff974SHong H. Pham 	struct cpuinfo_node *node = &t->nodes[node_index];
300280ff974SHong H. Pham 	int top_level, level;
301280ff974SHong H. Pham 
302280ff974SHong H. Pham 	top_level = t->nodes[root_index].level;
303280ff974SHong H. Pham 	for (level = node->level; level >= top_level; level--) {
304280ff974SHong H. Pham 		node->rover++;
305280ff974SHong H. Pham 		if (node->rover <= node->child_end)
306280ff974SHong H. Pham 			return;
307280ff974SHong H. Pham 
308280ff974SHong H. Pham 		node->rover = node->child_start;
309280ff974SHong H. Pham 		/* If parent's rover does not need to be adjusted, stop here. */
310280ff974SHong H. Pham 		if ((level == top_level) ||
311280ff974SHong H. Pham 		    !(rover_inc_table[level] & ROVER_INC_PARENT_ON_LOOP))
312280ff974SHong H. Pham 			return;
313280ff974SHong H. Pham 
314280ff974SHong H. Pham 		node = &t->nodes[node->parent_index];
315280ff974SHong H. Pham 	}
316280ff974SHong H. Pham }
317280ff974SHong H. Pham 
iterate_cpu(struct cpuinfo_tree * t,unsigned int root_index)318280ff974SHong H. Pham static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
319280ff974SHong H. Pham {
320280ff974SHong H. Pham 	const int *rover_inc_table;
321280ff974SHong H. Pham 	int level, new_index, index = root_index;
322280ff974SHong H. Pham 
323280ff974SHong H. Pham 	switch (sun4v_chip_type) {
324280ff974SHong H. Pham 	case SUN4V_CHIP_NIAGARA1:
325280ff974SHong H. Pham 	case SUN4V_CHIP_NIAGARA2:
3264ba991d3SDavid S. Miller 	case SUN4V_CHIP_NIAGARA3:
32708cefa9fSDavid S. Miller 	case SUN4V_CHIP_NIAGARA4:
32808cefa9fSDavid S. Miller 	case SUN4V_CHIP_NIAGARA5:
3299bd3ee33SAllen Pais 	case SUN4V_CHIP_SPARC_M6:
3309bd3ee33SAllen Pais 	case SUN4V_CHIP_SPARC_M7:
3317d484acbSAllen Pais 	case SUN4V_CHIP_SPARC_M8:
332c5b8b5beSKhalid Aziz 	case SUN4V_CHIP_SPARC_SN:
333a84ae809SAllen Pais 	case SUN4V_CHIP_SPARC64X:
334280ff974SHong H. Pham 		rover_inc_table = niagara_iterate_method;
335280ff974SHong H. Pham 		break;
336280ff974SHong H. Pham 	default:
337280ff974SHong H. Pham 		rover_inc_table = generic_iterate_method;
338280ff974SHong H. Pham 	}
339280ff974SHong H. Pham 
340280ff974SHong H. Pham 	for (level = t->nodes[root_index].level; level < CPUINFO_LVL_MAX;
341280ff974SHong H. Pham 	     level++) {
342280ff974SHong H. Pham 		new_index = t->nodes[index].rover;
343280ff974SHong H. Pham 		if (rover_inc_table[level] & ROVER_INC_ON_VISIT)
344280ff974SHong H. Pham 			increment_rover(t, index, root_index, rover_inc_table);
345280ff974SHong H. Pham 
346280ff974SHong H. Pham 		index = new_index;
347280ff974SHong H. Pham 	}
348280ff974SHong H. Pham 	return index;
349280ff974SHong H. Pham }
350280ff974SHong H. Pham 
_cpu_map_rebuild(void)351280ff974SHong H. Pham static void _cpu_map_rebuild(void)
352280ff974SHong H. Pham {
353280ff974SHong H. Pham 	int i;
354280ff974SHong H. Pham 
355280ff974SHong H. Pham 	if (cpuinfo_tree) {
356280ff974SHong H. Pham 		kfree(cpuinfo_tree);
357280ff974SHong H. Pham 		cpuinfo_tree = NULL;
358280ff974SHong H. Pham 	}
359280ff974SHong H. Pham 
360280ff974SHong H. Pham 	cpuinfo_tree = build_cpuinfo_tree();
361280ff974SHong H. Pham 	if (!cpuinfo_tree)
362280ff974SHong H. Pham 		return;
363280ff974SHong H. Pham 
364280ff974SHong H. Pham 	/* Build CPU distribution map that spans all online CPUs.  No need
365280ff974SHong H. Pham 	 * to check if the CPU is online, as that is done when the cpuinfo
366280ff974SHong H. Pham 	 * tree is being built.
367280ff974SHong H. Pham 	 */
368280ff974SHong H. Pham 	for (i = 0; i < cpuinfo_tree->nodes[0].num_cpus; i++)
369280ff974SHong H. Pham 		cpu_distribution_map[i] = iterate_cpu(cpuinfo_tree, 0);
370280ff974SHong H. Pham }
371280ff974SHong H. Pham 
372280ff974SHong H. Pham /* Fallback if the cpuinfo tree could not be built.  CPU mapping is linear
373280ff974SHong H. Pham  * round robin.
374280ff974SHong H. Pham  */
simple_map_to_cpu(unsigned int index)375280ff974SHong H. Pham static int simple_map_to_cpu(unsigned int index)
376280ff974SHong H. Pham {
377280ff974SHong H. Pham 	int i, end, cpu_rover;
378280ff974SHong H. Pham 
379280ff974SHong H. Pham 	cpu_rover = 0;
380280ff974SHong H. Pham 	end = index % num_online_cpus();
381280ff974SHong H. Pham 	for (i = 0; i < num_possible_cpus(); i++) {
382280ff974SHong H. Pham 		if (cpu_online(cpu_rover)) {
383280ff974SHong H. Pham 			if (cpu_rover >= end)
384280ff974SHong H. Pham 				return cpu_rover;
385280ff974SHong H. Pham 
386280ff974SHong H. Pham 			cpu_rover++;
387280ff974SHong H. Pham 		}
388280ff974SHong H. Pham 	}
389280ff974SHong H. Pham 
390280ff974SHong H. Pham 	/* Impossible, since num_online_cpus() <= num_possible_cpus() */
391fb1fece5SKOSAKI Motohiro 	return cpumask_first(cpu_online_mask);
392280ff974SHong H. Pham }
393280ff974SHong H. Pham 
_map_to_cpu(unsigned int index)394280ff974SHong H. Pham static int _map_to_cpu(unsigned int index)
395280ff974SHong H. Pham {
396280ff974SHong H. Pham 	struct cpuinfo_node *root_node;
397280ff974SHong H. Pham 
398280ff974SHong H. Pham 	if (unlikely(!cpuinfo_tree)) {
399280ff974SHong H. Pham 		_cpu_map_rebuild();
400280ff974SHong H. Pham 		if (!cpuinfo_tree)
401280ff974SHong H. Pham 			return simple_map_to_cpu(index);
402280ff974SHong H. Pham 	}
403280ff974SHong H. Pham 
404280ff974SHong H. Pham 	root_node = &cpuinfo_tree->nodes[0];
405280ff974SHong H. Pham #ifdef CONFIG_HOTPLUG_CPU
406280ff974SHong H. Pham 	if (unlikely(root_node->num_cpus != num_online_cpus())) {
407280ff974SHong H. Pham 		_cpu_map_rebuild();
408280ff974SHong H. Pham 		if (!cpuinfo_tree)
409280ff974SHong H. Pham 			return simple_map_to_cpu(index);
410280ff974SHong H. Pham 	}
411280ff974SHong H. Pham #endif
412280ff974SHong H. Pham 	return cpu_distribution_map[index % root_node->num_cpus];
413280ff974SHong H. Pham }
414280ff974SHong H. Pham 
map_to_cpu(unsigned int index)415280ff974SHong H. Pham int map_to_cpu(unsigned int index)
416280ff974SHong H. Pham {
417280ff974SHong H. Pham 	int mapped_cpu;
418280ff974SHong H. Pham 	unsigned long flag;
419280ff974SHong H. Pham 
420280ff974SHong H. Pham 	spin_lock_irqsave(&cpu_map_lock, flag);
421280ff974SHong H. Pham 	mapped_cpu = _map_to_cpu(index);
422280ff974SHong H. Pham 
423280ff974SHong H. Pham #ifdef CONFIG_HOTPLUG_CPU
424280ff974SHong H. Pham 	while (unlikely(!cpu_online(mapped_cpu)))
425280ff974SHong H. Pham 		mapped_cpu = _map_to_cpu(index);
426280ff974SHong H. Pham #endif
427280ff974SHong H. Pham 	spin_unlock_irqrestore(&cpu_map_lock, flag);
428280ff974SHong H. Pham 	return mapped_cpu;
429280ff974SHong H. Pham }
430280ff974SHong H. Pham EXPORT_SYMBOL(map_to_cpu);
431280ff974SHong H. Pham 
cpu_map_rebuild(void)432280ff974SHong H. Pham void cpu_map_rebuild(void)
433280ff974SHong H. Pham {
434280ff974SHong H. Pham 	unsigned long flag;
435280ff974SHong H. Pham 
436280ff974SHong H. Pham 	spin_lock_irqsave(&cpu_map_lock, flag);
437280ff974SHong H. Pham 	_cpu_map_rebuild();
438280ff974SHong H. Pham 	spin_unlock_irqrestore(&cpu_map_lock, flag);
439280ff974SHong H. Pham }
440