[PATCH 5/7] drm/amdgpu: Fix VCRAT proximity domain mappings for GPU nodes

Donet Tom <[email protected]> Tue, 4 Aug 2026 15:22:34 +0530
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <93378702b915679811543bf162e9424ee02382a7.1785833981.git.donettom@linux.ibm.com>
The VCRAT CPU builder, kfd_create_vcrat_image_cpu(), assigns proximity
domains sequentially while iterating over for_each_online_node(). As a
result, the first online node is assigned proximity domain 0, the second
online node is assigned proximity domain 1, and so on.

The GPU VCRAT builder creates GPU proximity domains after the CPU
proximity domains and programs the GPU-to-CPU affinity
(proximity_domain_to) using the NUMA node ID of the node to which the
GPU is attached. This is only correct when NUMA node IDs are contiguous,
because the CPU proximity domains happen to match the NUMA node IDs.

On systems with discontiguous NUMA node IDs, the CPU proximity domains no
longer correspond to the NUMA node IDs. For example:

available: 3 nodes (0,2,4)

Node IDs:           0    2    4
CPU proximity:      0    1    2
GPU proximity:                3

In this example, a GPU attached to NUMA node 4 is assigned GPU proximity
domain 3. However, its proximity_domain_to field is programmed with the
NUMA node ID (4) instead of the corresponding CPU proximity domain (2).

During VCRAT parsing, no CPU proximity domain with value 4 exists, so the
GPU affinity cannot be resolved and topology initialization fails:

amdgpu: Virtual CRAT table created for GPU
amdgpu: Error parsing VCRAT
kfd: amdgpu: Error adding device to topology
kfd: amdgpu: Error initializing KFD node

Fix this by translating the GPU's NUMA node ID to the corresponding CPU
proximity domain assigned during GPU VCRAT creation before programming
proximity_domain_to. This ensures that GPU affinity entries always
reference a valid CPU proximity domain, allowing VCRAT parsing and KFD
topology initialization to succeed on systems with discontiguous NUMA node
IDs.

Signed-off-by: Donet Tom <[email protected]>
---
 drivers/gpu/drm/amd/amdkfd/kfd_crat.c     | 10 +++++++---
 drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 22 ++++++++++++++++++++++
 drivers/gpu/drm/amd/amdkfd/kfd_topology.h |  2 ++
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index 079bce6d904d..b38208965fc8 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -1267,6 +1267,7 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink,
 					iolink->recommended_transfer_size;
 
 			dev->node_props.io_links_count++;
+			dev->numa_node = kfd_proximity_domain_to_numa_node(id_to);
 			list_add_tail(&props->list, &dev->io_link_props);
 			break;
 		}
@@ -1888,8 +1889,10 @@ static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size,
 		sub_type_hdr->flags = CRAT_SUBTYPE_FLAGS_ENABLED;
 
 		/* Fill in IO link data */
-		sub_type_hdr->proximity_domain_from = numa_node_id;
-		sub_type_hdr->proximity_domain_to = nid;
+		sub_type_hdr->proximity_domain_from =
+			kfd_numa_node_to_proximity_domain(numa_node_id);
+		sub_type_hdr->proximity_domain_to =
+			kfd_numa_node_to_proximity_domain(nid);
 		sub_type_hdr->io_interface_type = link_type;
 
 		(*num_entries)++;
@@ -2237,7 +2240,8 @@ static int kfd_fill_gpu_direct_io_link_to_cpu(int *avail_size,
 	if (kdev->adev->pdev->dev.numa_node == NUMA_NO_NODE)
 		sub_type_hdr->proximity_domain_to = 0;
 	else
-		sub_type_hdr->proximity_domain_to = kdev->adev->pdev->dev.numa_node;
+		sub_type_hdr->proximity_domain_to =
+		    kfd_numa_node_to_proximity_domain(kdev->adev->pdev->dev.numa_node);
 #else
 	sub_type_hdr->proximity_domain_to = 0;
 #endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index f4b7cb44daff..d3269f0ffec3 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -2463,3 +2463,25 @@ void kfd_update_svm_support_properties(struct amdgpu_device *adev)
 	}
 	up_write(&topology_lock);
 }
+
+int kfd_proximity_domain_to_numa_node(uint32_t proximity_domain)
+{
+	struct kfd_topology_device *dev;
+
+	list_for_each_entry(dev, &topology_device_list, list) {
+		if (dev->proximity_domain == proximity_domain)
+			return dev->numa_node;
+	}
+	return -1;
+}
+
+int kfd_numa_node_to_proximity_domain(int target_node)
+{
+	struct kfd_topology_device *dev;
+
+	list_for_each_entry(dev, &topology_device_list, list) {
+		if (dev->numa_node == target_node)
+			return dev->proximity_domain;
+	}
+	return -1;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
index f5e00f5df922..312802754096 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
@@ -201,6 +201,8 @@ struct dmi_mem_device {
 struct kfd_topology_device *kfd_create_topology_device(
 		struct list_head *device_list);
 void kfd_release_topology_device_list(struct list_head *device_list);
+int kfd_numa_node_to_proximity_domain(int target_node);
+int kfd_proximity_domain_to_numa_node(uint32_t proximity_domain);
 
 #if IS_ENABLED(CONFIG_HSA_AMD)
 void kfd_update_svm_support_properties(struct amdgpu_device *adev);
-- 
2.54.0