@@ -100,6 +100,19 @@ unsigned int __init arch_get_dma_bitsize(void)
+ PAGE_SHIFT, 32);
}
+/**
+ * @brief Retrieves the RAM range for a given index from the e820 memory map.
+ *
+ * This function fetches the start and end address (exclusive) of a RAM range
+ * specified by the given index idx from the e820 memory map.
+ *
+ * @param idx The index of the RAM range in the e820 memory map to retrieve.
+ * @param start Pointer to store the start address of the RAM range.
+ * @param end Pointer to store the end address of the RAM range.
+ *
+ * @return 0 on success, -ENOENT if the index is out of bounds,
+ * or -ENODATA if the memory map at index idx is not of type E820_RAM.
+ */
int __init arch_get_ram_range(unsigned int idx, paddr_t *start, paddr_t *end)
{
if ( idx >= e820.nr_map )
@@ -1334,6 +1334,9 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm)
share_hotadd_m2p_table(&info);
transfer_pages_to_heap(&info);
+ /* Update the node's present pages (like the total_pages of the system) */
+ NODE_DATA(node)->node_present_pages += epfn - spfn;
+
return 0;
destroy_m2p:
@@ -4,6 +4,7 @@
* Adapted for Xen: Ryan Harper <ryanh@us.ibm.com>
*/
+#include "xen/pfn.h"
#include <xen/init.h>
#include <xen/keyhandler.h>
#include <xen/mm.h>
@@ -499,15 +500,44 @@ int __init compute_hash_shift(const struct node *nodes,
return shift;
}
-/* Initialize NODE_DATA given nodeid and start/end */
+/**
+ * @brief Initialize a NUMA node's node_data structure at boot.
+ *
+ * It is given the NUMA node's index in the node_data array as well
+ * as the start and exclusive end address of the node's memory span
+ * as arguments and initializes the node_data entry with this information.
+ *
+ * It then initializes the total number of usable memory pages within
+ * the NUMA node's memory span using the arch_get_ram_range() function.
+ *
+ * @param nodeid The index into the node_data array for the node.
+ * @param start The starting physical address of the node's memory range.
+ * @param end The exclusive ending physical address of the node's memory range.
+ */
void __init setup_node_bootmem(nodeid_t nodeid, paddr_t start, paddr_t end)
{
unsigned long start_pfn = paddr_to_pfn(start);
unsigned long end_pfn = paddr_to_pfn(end);
+ struct node_data *numa_node = NODE_DATA(nodeid);
+ paddr_t start_ram, end_ram;
+ unsigned int idx = 0;
+ unsigned long *pages = &numa_node->node_present_pages;
- NODE_DATA(nodeid)->node_start_pfn = start_pfn;
- NODE_DATA(nodeid)->node_spanned_pages = end_pfn - start_pfn;
+ numa_node->node_start_pfn = start_pfn;
+ numa_node->node_spanned_pages = end_pfn - start_pfn;
+
+ /* Calculate the number of present RAM pages within the node: */
+ *pages = 0;
+ do {
+ int err = arch_get_ram_range(idx++, &start_ram, &end_ram);
+
+ if (err == -ENOENT)
+ break;
+ if ( err || start_ram >= end || end_ram <= start )
+ continue; /* range is outside of the node, or not usable RAM */
+ *pages += PFN_DOWN(min(end_ram, end)) - PFN_UP(max(start_ram, start));
+ } while (1);
node_set_online(nodeid);
}
@@ -68,9 +68,28 @@ extern unsigned int memnode_shift;
extern unsigned long memnodemapsize;
extern nodeid_t *memnodemap;
+/**
+ * @struct numa_node
+ * @brief Represents the memory information of a NUMA node.
+ *
+ * @var numa_node::node_start_pfn
+ * The starting page frame number (lowest pfn) of the NUMA node.
+ *
+ * @var numa_node::node_spanned_pages
+ * The number of pages spanned by the NUMA node, including memory holes.
+ * Used to get the end of the node memory when scrubbing unallocated memory.
+ *
+ * @var numa_node::node_present_pages
+ * The total number of usable memory pages that are available in this NUMA node.
+ * The value of total_pages would be the sum of all node's node_present_pages.
+ *
+ * The Xen Hypervisor does not use this field internally, but it is useful
+ * for reporting the memory information of NUMA nodes to management tools.
+ */
struct node_data {
unsigned long node_start_pfn;
unsigned long node_spanned_pages;
+ unsigned long node_present_pages;
};
extern struct node_data node_data[];
@@ -91,6 +110,7 @@ static inline nodeid_t mfn_to_nid(mfn_t mfn)
#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
#define node_spanned_pages(nid) (NODE_DATA(nid)->node_spanned_pages)
+#define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages)
#define node_end_pfn(nid) (NODE_DATA(nid)->node_start_pfn + \
NODE_DATA(nid)->node_spanned_pages)
@@ -123,6 +143,7 @@ extern void numa_set_processor_nodes_parsed(nodeid_t node);
extern mfn_t first_valid_mfn;
#define node_spanned_pages(nid) (max_page - mfn_x(first_valid_mfn))
+#define node_present_pages(nid) total_pages
#define node_start_pfn(nid) mfn_x(first_valid_mfn)
#define __node_distance(a, b) 20