aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/numa.c209
1 files changed, 170 insertions, 39 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index dc704da363eb..39328da32edf 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -268,6 +268,144 @@ static unsigned long __devinit read_n_cells(int n, const unsigned int **buf)
268 return result; 268 return result;
269} 269}
270 270
271struct of_drconf_cell {
272 u64 base_addr;
273 u32 drc_index;
274 u32 reserved;
275 u32 aa_index;
276 u32 flags;
277};
278
279#define DRCONF_MEM_ASSIGNED 0x00000008
280#define DRCONF_MEM_AI_INVALID 0x00000040
281#define DRCONF_MEM_RESERVED 0x00000080
282
283/*
284 * Read the next lmb list entry from the ibm,dynamic-memory property
285 * and return the information in the provided of_drconf_cell structure.
286 */
287static void read_drconf_cell(struct of_drconf_cell *drmem, const u32 **cellp)
288{
289 const u32 *cp;
290
291 drmem->base_addr = read_n_cells(n_mem_addr_cells, cellp);
292
293 cp = *cellp;
294 drmem->drc_index = cp[0];
295 drmem->reserved = cp[1];
296 drmem->aa_index = cp[2];
297 drmem->flags = cp[3];
298
299 *cellp = cp + 4;
300}
301
302/*
303 * Retreive and validate the ibm,dynamic-memory property of the device tree.
304 *
305 * The layout of the ibm,dynamic-memory property is a number N of lmb
306 * list entries followed by N lmb list entries. Each lmb list entry
307 * contains information as layed out in the of_drconf_cell struct above.
308 */
309static int of_get_drconf_memory(struct device_node *memory, const u32 **dm)
310{
311 const u32 *prop;
312 u32 len, entries;
313
314 prop = of_get_property(memory, "ibm,dynamic-memory", &len);
315 if (!prop || len < sizeof(unsigned int))
316 return 0;
317
318 entries = *prop++;
319
320 /* Now that we know the number of entries, revalidate the size
321 * of the property read in to ensure we have everything
322 */
323 if (len < (entries * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int))
324 return 0;
325
326 *dm = prop;
327 return entries;
328}
329
330/*
331 * Retreive and validate the ibm,lmb-size property for drconf memory
332 * from the device tree.
333 */
334static u64 of_get_lmb_size(struct device_node *memory)
335{
336 const u32 *prop;
337 u32 len;
338
339 prop = of_get_property(memory, "ibm,lmb-size", &len);
340 if (!prop || len < sizeof(unsigned int))
341 return 0;
342
343 return read_n_cells(n_mem_size_cells, &prop);
344}
345
346struct assoc_arrays {
347 u32 n_arrays;
348 u32 array_sz;
349 const u32 *arrays;
350};
351
352/*
353 * Retreive and validate the list of associativity arrays for drconf
354 * memory from the ibm,associativity-lookup-arrays property of the
355 * device tree..
356 *
357 * The layout of the ibm,associativity-lookup-arrays property is a number N
358 * indicating the number of associativity arrays, followed by a number M
359 * indicating the size of each associativity array, followed by a list
360 * of N associativity arrays.
361 */
362static int of_get_assoc_arrays(struct device_node *memory,
363 struct assoc_arrays *aa)
364{
365 const u32 *prop;
366 u32 len;
367
368 prop = of_get_property(memory, "ibm,associativity-lookup-arrays", &len);
369 if (!prop || len < 2 * sizeof(unsigned int))
370 return -1;
371
372 aa->n_arrays = *prop++;
373 aa->array_sz = *prop++;
374
375 /* Now that we know the number of arrrays and size of each array,
376 * revalidate the size of the property read in.
377 */
378 if (len < (aa->n_arrays * aa->array_sz + 2) * sizeof(unsigned int))
379 return -1;
380
381 aa->arrays = prop;
382 return 0;
383}
384
385/*
386 * This is like of_node_to_nid_single() for memory represented in the
387 * ibm,dynamic-reconfiguration-memory node.
388 */
389static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
390 struct assoc_arrays *aa)
391{
392 int default_nid = 0;
393 int nid = default_nid;
394 int index;
395
396 if (min_common_depth > 0 && min_common_depth <= aa->array_sz &&
397 !(drmem->flags & DRCONF_MEM_AI_INVALID) &&
398 drmem->aa_index < aa->n_arrays) {
399 index = drmem->aa_index * aa->array_sz + min_common_depth - 1;
400 nid = aa->arrays[index];
401
402 if (nid == 0xffff || nid >= MAX_NUMNODES)
403 nid = default_nid;
404 }
405
406 return nid;
407}
408
271/* 409/*
272 * Figure out to which domain a cpu belongs and stick it there. 410 * Figure out to which domain a cpu belongs and stick it there.
273 * Return the id of the domain used. 411 * Return the id of the domain used.
@@ -355,57 +493,50 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
355 */ 493 */
356static void __init parse_drconf_memory(struct device_node *memory) 494static void __init parse_drconf_memory(struct device_node *memory)
357{ 495{
358 const unsigned int *lm, *dm, *aa; 496 const u32 *dm;
359 unsigned int ls, ld, la; 497 unsigned int n, rc;
360 unsigned int n, aam, aalen; 498 unsigned long lmb_size, size;
361 unsigned long lmb_size, size, start; 499 int nid;
362 int nid, default_nid = 0; 500 struct assoc_arrays aa;
363 unsigned int ai, flags; 501
364 502 n = of_get_drconf_memory(memory, &dm);
365 lm = of_get_property(memory, "ibm,lmb-size", &ls); 503 if (!n)
366 dm = of_get_property(memory, "ibm,dynamic-memory", &ld);
367 aa = of_get_property(memory, "ibm,associativity-lookup-arrays", &la);
368 if (!lm || !dm || !aa ||
369 ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
370 la < 2 * sizeof(unsigned int))
371 return; 504 return;
372 505
373 lmb_size = read_n_cells(n_mem_size_cells, &lm); 506 lmb_size = of_get_lmb_size(memory);
374 n = *dm++; /* number of LMBs */ 507 if (!lmb_size)
375 aam = *aa++; /* number of associativity lists */ 508 return;
376 aalen = *aa++; /* length of each associativity list */ 509
377 if (ld < (n * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int) || 510 rc = of_get_assoc_arrays(memory, &aa);
378 la < (aam * aalen + 2) * sizeof(unsigned int)) 511 if (rc)
379 return; 512 return;
380 513
381 for (; n != 0; --n) { 514 for (; n != 0; --n) {
382 start = read_n_cells(n_mem_addr_cells, &dm); 515 struct of_drconf_cell drmem;
383 ai = dm[2]; 516
384 flags = dm[3]; 517 read_drconf_cell(&drmem, &dm);
385 dm += 4; 518
386 /* 0x80 == reserved, 0x8 = assigned to us */ 519 /* skip this block if the reserved bit is set in flags (0x80)
387 if ((flags & 0x80) || !(flags & 0x8)) 520 or if the block is not assigned to this partition (0x8) */
521 if ((drmem.flags & DRCONF_MEM_RESERVED)
522 || !(drmem.flags & DRCONF_MEM_ASSIGNED))
388 continue; 523 continue;
389 nid = default_nid;
390 /* flags & 0x40 means associativity index is invalid */
391 if (min_common_depth > 0 && min_common_depth <= aalen &&
392 (flags & 0x40) == 0 && ai < aam) {
393 /* this is like of_node_to_nid_single */
394 nid = aa[ai * aalen + min_common_depth - 1];
395 if (nid == 0xffff || nid >= MAX_NUMNODES)
396 nid = default_nid;
397 }
398 524
399 fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT), 525 nid = of_drconf_to_nid_single(&drmem, &aa);
400 &nid); 526
527 fake_numa_create_new_node(
528 ((drmem.base_addr + lmb_size) >> PAGE_SHIFT),
529 &nid);
530
401 node_set_online(nid); 531 node_set_online(nid);
402 532
403 size = numa_enforce_memory_limit(start, lmb_size); 533 size = numa_enforce_memory_limit(drmem.base_addr, lmb_size);
404 if (!size) 534 if (!size)
405 continue; 535 continue;
406 536
407 add_active_range(nid, start >> PAGE_SHIFT, 537 add_active_range(nid, drmem.base_addr >> PAGE_SHIFT,
408 (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT)); 538 (drmem.base_addr >> PAGE_SHIFT)
539 + (size >> PAGE_SHIFT));
409 } 540 }
410} 541}
411 542