@@ -42,6 +42,12 @@ EXPORT_SYMBOL(node_data);
42
42
43
43
static int min_common_depth ;
44
44
static int n_mem_addr_cells , n_mem_size_cells ;
45
+ static int form1_affinity ;
46
+
47
+ #define MAX_DISTANCE_REF_POINTS 4
48
+ static int distance_ref_points_depth ;
49
+ static const unsigned int * distance_ref_points ;
50
+ static int distance_lookup_table [MAX_NUMNODES ][MAX_DISTANCE_REF_POINTS ];
45
51
46
52
/*
47
53
* Allocate node_to_cpumask_map based on number of available nodes
@@ -204,6 +210,39 @@ static const u32 *of_get_usable_memory(struct device_node *memory)
204
210
return prop ;
205
211
}
206
212
213
+ int __node_distance (int a , int b )
214
+ {
215
+ int i ;
216
+ int distance = LOCAL_DISTANCE ;
217
+
218
+ if (!form1_affinity )
219
+ return distance ;
220
+
221
+ for (i = 0 ; i < distance_ref_points_depth ; i ++ ) {
222
+ if (distance_lookup_table [a ][i ] == distance_lookup_table [b ][i ])
223
+ break ;
224
+
225
+ /* Double the distance for each NUMA level */
226
+ distance *= 2 ;
227
+ }
228
+
229
+ return distance ;
230
+ }
231
+
232
+ static void initialize_distance_lookup_table (int nid ,
233
+ const unsigned int * associativity )
234
+ {
235
+ int i ;
236
+
237
+ if (!form1_affinity )
238
+ return ;
239
+
240
+ for (i = 0 ; i < distance_ref_points_depth ; i ++ ) {
241
+ distance_lookup_table [nid ][i ] =
242
+ associativity [distance_ref_points [i ]];
243
+ }
244
+ }
245
+
207
246
/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
208
247
* info is found.
209
248
*/
@@ -225,6 +264,10 @@ static int of_node_to_nid_single(struct device_node *device)
225
264
/* POWER4 LPAR uses 0xffff as invalid node */
226
265
if (nid == 0xffff || nid >= MAX_NUMNODES )
227
266
nid = -1 ;
267
+
268
+ if (nid > 0 && tmp [0 ] >= distance_ref_points_depth )
269
+ initialize_distance_lookup_table (nid , tmp );
270
+
228
271
out :
229
272
return nid ;
230
273
}
@@ -251,26 +294,10 @@ int of_node_to_nid(struct device_node *device)
251
294
}
252
295
EXPORT_SYMBOL_GPL (of_node_to_nid );
253
296
254
- /*
255
- * In theory, the "ibm,associativity" property may contain multiple
256
- * associativity lists because a resource may be multiply connected
257
- * into the machine. This resource then has different associativity
258
- * characteristics relative to its multiple connections. We ignore
259
- * this for now. We also assume that all cpu and memory sets have
260
- * their distances represented at a common level. This won't be
261
- * true for hierarchical NUMA.
262
- *
263
- * In any case the ibm,associativity-reference-points should give
264
- * the correct depth for a normal NUMA system.
265
- *
266
- * - Dave Hansen <[email protected] >
267
- */
268
297
static int __init find_min_common_depth (void )
269
298
{
270
- int depth , index ;
271
- const unsigned int * ref_points ;
299
+ int depth ;
272
300
struct device_node * rtas_root ;
273
- unsigned int len ;
274
301
struct device_node * chosen ;
275
302
const char * vec5 ;
276
303
@@ -280,38 +307,67 @@ static int __init find_min_common_depth(void)
280
307
return -1 ;
281
308
282
309
/*
283
- * this property is 2 32-bit integers, each representing a level of
284
- * depth in the associativity nodes. The first is for an SMP
285
- * configuration (should be all 0's) and the second is for a normal
286
- * NUMA configuration.
310
+ * This property is a set of 32-bit integers, each representing
311
+ * an index into the ibm,associativity nodes.
312
+ *
313
+ * With form 0 affinity the first integer is for an SMP configuration
314
+ * (should be all 0's) and the second is for a normal NUMA
315
+ * configuration. We have only one level of NUMA.
316
+ *
317
+ * With form 1 affinity the first integer is the most significant
318
+ * NUMA boundary and the following are progressively less significant
319
+ * boundaries. There can be more than one level of NUMA.
287
320
*/
288
- index = 1 ;
289
- ref_points = of_get_property (rtas_root ,
290
- "ibm,associativity-reference-points" , & len );
321
+ distance_ref_points = of_get_property (rtas_root ,
322
+ "ibm,associativity-reference-points" ,
323
+ & distance_ref_points_depth );
324
+
325
+ if (!distance_ref_points ) {
326
+ dbg ("NUMA: ibm,associativity-reference-points not found.\n" );
327
+ goto err ;
328
+ }
329
+
330
+ distance_ref_points_depth /= sizeof (int );
291
331
292
- /*
293
- * For form 1 affinity information we want the first field
294
- */
295
332
#define VEC5_AFFINITY_BYTE 5
296
333
#define VEC5_AFFINITY 0x80
297
334
chosen = of_find_node_by_path ("/chosen" );
298
335
if (chosen ) {
299
336
vec5 = of_get_property (chosen , "ibm,architecture-vec-5" , NULL );
300
337
if (vec5 && (vec5 [VEC5_AFFINITY_BYTE ] & VEC5_AFFINITY )) {
301
338
dbg ("Using form 1 affinity\n" );
302
- index = 0 ;
339
+ form1_affinity = 1 ;
303
340
}
304
341
}
305
342
306
- if (( len >= 2 * sizeof ( unsigned int )) && ref_points ) {
307
- depth = ref_points [ index ];
343
+ if (form1_affinity ) {
344
+ depth = distance_ref_points [ 0 ];
308
345
} else {
309
- dbg ("NUMA: ibm,associativity-reference-points not found.\n" );
310
- depth = -1 ;
346
+ if (distance_ref_points_depth < 2 ) {
347
+ printk (KERN_WARNING "NUMA: "
348
+ "short ibm,associativity-reference-points\n" );
349
+ goto err ;
350
+ }
351
+
352
+ depth = distance_ref_points [1 ];
311
353
}
312
- of_node_put (rtas_root );
313
354
355
+ /*
356
+ * Warn and cap if the hardware supports more than
357
+ * MAX_DISTANCE_REF_POINTS domains.
358
+ */
359
+ if (distance_ref_points_depth > MAX_DISTANCE_REF_POINTS ) {
360
+ printk (KERN_WARNING "NUMA: distance array capped at "
361
+ "%d entries\n" , MAX_DISTANCE_REF_POINTS );
362
+ distance_ref_points_depth = MAX_DISTANCE_REF_POINTS ;
363
+ }
364
+
365
+ of_node_put (rtas_root );
314
366
return depth ;
367
+
368
+ err :
369
+ of_node_put (rtas_root );
370
+ return -1 ;
315
371
}
316
372
317
373
static void __init get_n_mem_cells (int * n_addr_cells , int * n_size_cells )
0 commit comments