numa.c 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /*
  2. * arch/sh/mm/numa.c - Multiple node support for SH machines
  3. *
  4. * Copyright (C) 2007 Paul Mundt
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file "COPYING" in the main directory of this archive
  8. * for more details.
  9. */
  10. #include <linux/module.h>
  11. #include <linux/bootmem.h>
  12. #include <linux/mm.h>
  13. #include <linux/numa.h>
  14. #include <linux/pfn.h>
  15. #include <asm/sections.h>
  16. static bootmem_data_t plat_node_bdata[MAX_NUMNODES];
  17. struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
  18. EXPORT_SYMBOL_GPL(node_data);
  19. /*
  20. * On SH machines the conventional approach is to stash system RAM
  21. * in node 0, and other memory blocks in to node 1 and up, ordered by
  22. * latency. Each node's pgdat is node-local at the beginning of the node,
  23. * immediately followed by the node mem map.
  24. */
  25. void __init setup_memory(void)
  26. {
  27. unsigned long free_pfn = PFN_UP(__pa(_end));
  28. /*
  29. * Node 0 sets up its pgdat at the first available pfn,
  30. * and bumps it up before setting up the bootmem allocator.
  31. */
  32. NODE_DATA(0) = pfn_to_kaddr(free_pfn);
  33. memset(NODE_DATA(0), 0, sizeof(struct pglist_data));
  34. free_pfn += PFN_UP(sizeof(struct pglist_data));
  35. NODE_DATA(0)->bdata = &plat_node_bdata[0];
  36. /* Set up node 0 */
  37. setup_bootmem_allocator(free_pfn);
  38. /* Give the platforms a chance to hook up their nodes */
  39. plat_mem_setup();
  40. }
  41. void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
  42. {
  43. unsigned long bootmap_pages, bootmap_start, bootmap_size;
  44. unsigned long start_pfn, free_pfn, end_pfn;
  45. /* Don't allow bogus node assignment */
  46. BUG_ON(nid > MAX_NUMNODES || nid == 0);
  47. /*
  48. * The free pfn starts at the beginning of the range, and is
  49. * advanced as necessary for pgdat and node map allocations.
  50. */
  51. free_pfn = start_pfn = start >> PAGE_SHIFT;
  52. end_pfn = end >> PAGE_SHIFT;
  53. add_active_range(nid, start_pfn, end_pfn);
  54. /* Node-local pgdat */
  55. NODE_DATA(nid) = pfn_to_kaddr(free_pfn);
  56. free_pfn += PFN_UP(sizeof(struct pglist_data));
  57. memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
  58. NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
  59. NODE_DATA(nid)->node_start_pfn = start_pfn;
  60. NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn;
  61. /* Node-local bootmap */
  62. bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
  63. bootmap_start = (unsigned long)pfn_to_kaddr(free_pfn);
  64. bootmap_size = init_bootmem_node(NODE_DATA(nid), free_pfn, start_pfn,
  65. end_pfn);
  66. free_bootmem_with_active_regions(nid, end_pfn);
  67. /* Reserve the pgdat and bootmap space with the bootmem allocator */
  68. reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT,
  69. sizeof(struct pglist_data));
  70. reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT,
  71. bootmap_pages << PAGE_SHIFT);
  72. /* It's up */
  73. node_set_online(nid);
  74. /* Kick sparsemem */
  75. sparse_memory_present_with_active_regions(nid);
  76. }