bootmem_info.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Bootmem core functions.
  4. *
  5. * Copyright (c) 2020, Bytedance.
  6. *
  7. * Author: Muchun Song <songmuchun@bytedance.com>
  8. *
  9. */
  10. #include <linux/mm.h>
  11. #include <linux/compiler.h>
  12. #include <linux/memblock.h>
  13. #include <linux/bootmem_info.h>
  14. #include <linux/memory_hotplug.h>
  15. #include <linux/kmemleak.h>
  16. void get_page_bootmem(unsigned long info, struct page *page,
  17. enum bootmem_type type)
  18. {
  19. BUG_ON(type > 0xf);
  20. BUG_ON(info > (ULONG_MAX >> 4));
  21. SetPagePrivate(page);
  22. set_page_private(page, info << 4 | type);
  23. page_ref_inc(page);
  24. }
  25. void put_page_bootmem(struct page *page)
  26. {
  27. enum bootmem_type type = bootmem_type(page);
  28. BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE ||
  29. type > MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE);
  30. if (page_ref_dec_return(page) == 1) {
  31. ClearPagePrivate(page);
  32. set_page_private(page, 0);
  33. INIT_LIST_HEAD(&page->lru);
  34. kmemleak_free_part_phys(PFN_PHYS(page_to_pfn(page)), PAGE_SIZE);
  35. free_reserved_page(page);
  36. }
  37. }
  38. #ifndef CONFIG_SPARSEMEM_VMEMMAP
  39. static void __init register_page_bootmem_info_section(unsigned long start_pfn)
  40. {
  41. unsigned long mapsize, section_nr, i;
  42. struct mem_section *ms;
  43. struct page *page, *memmap;
  44. struct mem_section_usage *usage;
  45. section_nr = pfn_to_section_nr(start_pfn);
  46. ms = __nr_to_section(section_nr);
  47. /* Get section's memmap address */
  48. memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
  49. /*
  50. * Get page for the memmap's phys address
  51. * XXX: need more consideration for sparse_vmemmap...
  52. */
  53. page = virt_to_page(memmap);
  54. mapsize = sizeof(struct page) * PAGES_PER_SECTION;
  55. mapsize = PAGE_ALIGN(mapsize) >> PAGE_SHIFT;
  56. /* remember memmap's page */
  57. for (i = 0; i < mapsize; i++, page++)
  58. get_page_bootmem(section_nr, page, SECTION_INFO);
  59. usage = ms->usage;
  60. page = virt_to_page(usage);
  61. mapsize = PAGE_ALIGN(mem_section_usage_size()) >> PAGE_SHIFT;
  62. for (i = 0; i < mapsize; i++, page++)
  63. get_page_bootmem(section_nr, page, MIX_SECTION_INFO);
  64. }
  65. #else /* CONFIG_SPARSEMEM_VMEMMAP */
  66. static void __init register_page_bootmem_info_section(unsigned long start_pfn)
  67. {
  68. unsigned long mapsize, section_nr, i;
  69. struct mem_section *ms;
  70. struct page *page, *memmap;
  71. struct mem_section_usage *usage;
  72. section_nr = pfn_to_section_nr(start_pfn);
  73. ms = __nr_to_section(section_nr);
  74. memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
  75. if (!preinited_vmemmap_section(ms))
  76. register_page_bootmem_memmap(section_nr, memmap,
  77. PAGES_PER_SECTION);
  78. usage = ms->usage;
  79. page = virt_to_page(usage);
  80. mapsize = PAGE_ALIGN(mem_section_usage_size()) >> PAGE_SHIFT;
  81. for (i = 0; i < mapsize; i++, page++)
  82. get_page_bootmem(section_nr, page, MIX_SECTION_INFO);
  83. }
  84. #endif /* !CONFIG_SPARSEMEM_VMEMMAP */
  85. void __init register_page_bootmem_info_node(struct pglist_data *pgdat)
  86. {
  87. unsigned long i, pfn, end_pfn, nr_pages;
  88. int node = pgdat->node_id;
  89. struct page *page;
  90. nr_pages = PAGE_ALIGN(sizeof(struct pglist_data)) >> PAGE_SHIFT;
  91. page = virt_to_page(pgdat);
  92. for (i = 0; i < nr_pages; i++, page++)
  93. get_page_bootmem(node, page, NODE_INFO);
  94. pfn = pgdat->node_start_pfn;
  95. end_pfn = pgdat_end_pfn(pgdat);
  96. /* register section info */
  97. for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
  98. /*
  99. * Some platforms can assign the same pfn to multiple nodes - on
  100. * node0 as well as nodeN. To avoid registering a pfn against
  101. * multiple nodes we check that this pfn does not already
  102. * reside in some other nodes.
  103. */
  104. if (pfn_valid(pfn) && (early_pfn_to_nid(pfn) == node))
  105. register_page_bootmem_info_section(pfn);
  106. }
  107. }