[PATCH 6/7] drm/amdgpu: Create proximity domains and VCRAT entries for CPU-less and memory-less NUMA nodes

Donet Tom <[email protected]> Tue, 4 Aug 2026 15:22:35 +0530
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <0b31dfae2fb95800d6b58683a4f1ea03a5545653.1785833981.git.donettom@linux.ibm.com>
The current implementation creates proximity domains and the associated
VCRAT entries only for NUMA nodes that contain CPUs. However, Linux
systems can have CPU-less, memory-less, or CPU-less and memory-less
NUMA nodes.

When proximity domains and VCRAT entries are not created for these
NUMA nodes, the generated VCRAT is incomplete and KFD topology
initialization fails while parsing it.

For example:

  available: 3 nodes (0,2-3)

  node 0 cpus: 0-39
  node 0 size: 519305 MB

  node 2 cpus:
  node 2 size: 519305 MB

  node 3 cpus:
  node 3 size:

With the current implementation, only node 0 is assigned a CPU
proximity domain (domain 0). A GPU attached to NUMA node 3 is assigned
GPU proximity domain 1, and its proximity_domain_to field references
the CPU proximity domain corresponding to node 3. Since no CPU
proximity domain exists for node 3, the referenced proximity domain is
missing, causing VCRAT parsing to fail.

Fix this by creating proximity domains and the corresponding VCRAT
entries for all online NUMA nodes, including CPU-less and memory-less
nodes. This ensures that every online NUMA node has a corresponding
proximity domain, allowing GPU affinity information to be resolved
correctly during VCRAT parsing.

Signed-off-by: Donet Tom <[email protected]>
---
 drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 78 ++++++++++++++-------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index b38208965fc8..df698109c17a 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -1974,51 +1974,55 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size)
 	sub_type_hdr = (struct crat_subtype_generic *)(crat_table+1);
 
 	for_each_online_node(numa_node_id) {
-		if (kfd_numa_node_to_apic_id(numa_node_id) == -1)
-			continue;
-
-		/* Fill in Subtype: Compute Unit */
-		ret = kfd_fill_cu_for_cpu(numa_node_id, &avail_size,
-			crat_table->num_domains,
-			(struct crat_subtype_computeunit *)sub_type_hdr);
-		if (ret < 0)
-			return ret;
-		crat_table->length += sub_type_hdr->length;
-		crat_table->total_entries++;
+		int apic_id = kfd_numa_node_to_apic_id(numa_node_id);
+		int mem = node_state(numa_node_id, N_MEMORY);
+
+		if (apic_id != -1) {
+			/* Fill in Subtype: Compute Unit */
+			ret = kfd_fill_cu_for_cpu(numa_node_id, &avail_size,
+				crat_table->num_domains,
+				(struct crat_subtype_computeunit *)sub_type_hdr);
+			if (ret < 0)
+				return ret;
+			crat_table->length += sub_type_hdr->length;
+			crat_table->total_entries++;
 
-		sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
-			sub_type_hdr->length);
+			sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
+				sub_type_hdr->length);
 
-		/* Fill in Subtype: Memory */
-		ret = kfd_fill_mem_info_for_cpu(numa_node_id, &avail_size,
-			crat_table->num_domains,
-			(struct crat_subtype_memory *)sub_type_hdr);
-		if (ret < 0)
-			return ret;
-		crat_table->length += sub_type_hdr->length;
-		crat_table->total_entries++;
+			/* Fill in Subtype: IO Link */
+#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
+			ret = kfd_fill_iolink_info_for_cpu(numa_node_id, &avail_size,
+					&entries,
+					(struct crat_subtype_iolink *)sub_type_hdr);
+			if (ret < 0)
+				return ret;
 
-		sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
-			sub_type_hdr->length);
+			if (entries) {
+				crat_table->length += (sub_type_hdr->length * entries);
+				crat_table->total_entries += entries;
 
-		/* Fill in Subtype: IO Link */
-#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
-		ret = kfd_fill_iolink_info_for_cpu(numa_node_id, &avail_size,
-				&entries,
-				(struct crat_subtype_iolink *)sub_type_hdr);
-		if (ret < 0)
-			return ret;
+				sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
+						sub_type_hdr->length * entries);
+			}
+#else
+			pr_info("IO link not available for non x86 platforms\n");
+#endif
+		}
 
-		if (entries) {
-			crat_table->length += (sub_type_hdr->length * entries);
-			crat_table->total_entries += entries;
+		if (mem) {
+			/* Fill in Subtype: Memory */
+			ret = kfd_fill_mem_info_for_cpu(numa_node_id, &avail_size,
+				crat_table->num_domains,
+				(struct crat_subtype_memory *)sub_type_hdr);
+			if (ret < 0)
+				return ret;
+			crat_table->length += sub_type_hdr->length;
+			crat_table->total_entries++;
 
 			sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
-					sub_type_hdr->length * entries);
+				sub_type_hdr->length);
 		}
-#else
-		pr_info("IO link not available for non x86 platforms\n");
-#endif
 
 		ret = kfd_fill_numa_info_for_cpu(&avail_size,
 				(struct crat_subtype_numa *)sub_type_hdr,
-- 
2.54.0