On A+A the GPU HBM is exposed as specific-purpose memory described by
SRAT, and the GPU reaches it at a system physical address over the
internal link, so the driver needs a way to discover that range.

Add amdgpu_acpi_find_gpu_memory_in_srat(), which resolves the GPU
proximity domain from the SRAT GENERIC_AFFINITY entry matching the PCI
device handle, then returns the enabled, non-hotpluggable memory range
of that domain.

No caller yet, the users follow.

v2:
- A+A VF/passthrough is identified later by missing FB BAR0
  (AMDGPU_VIRT_VRAM_IS_SPM), not by xgmi.connected_to_cpu.

v3:
- Rename best_base/best_len to mem_base/mem_len; first match, not a
  comparison.
- Drop the unused legacy packed-BDF PCI handle format.
- Log "no acpi generic initiator found" without extra PCI BDF.
- Use dev_err for error-return logs.

v4:
- Reverse Christmas-tree local declarations, one per line.
- Reject NULL base_addr/length with -EINVAL.

Signed-off-by: Zhigang Luo <[email protected]>
Signed-off-by: Fangsheng Huang <[email protected]>
Signed-off-by: YuBiao Wang <[email protected]>
Reviewed-by: Lijo Lazar <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 136 +++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h |   7 ++
 2 files changed, 143 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 7f5abb03be1b..d46ebbb5e811 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/xarray.h>
 #include <linux/power_supply.h>
+#include <linux/numa.h>
 #include <linux/pm_runtime.h>
 #include <linux/suspend.h>
 #include <acpi/video.h>
@@ -1445,6 +1446,141 @@ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device 
*adev)
 #endif
 }
 
+#ifdef HAVE_ACPI_SRAT_GENERIC_AFFINITY
+static bool amdgpu_acpi_srat_pci_handle_match(struct pci_dev *pdev,
+                                             struct acpi_srat_generic_affinity 
*gi)
+{
+       u16 segment = *(u16 *)&gi->device_handle[0];
+       u8 bus = gi->device_handle[2];
+       u8 devfn = gi->device_handle[3];
+
+       /* Only PCI device handles (ACPI 6.3: type 1; some firmware used 0) */
+       if (gi->device_handle_type != 0 && gi->device_handle_type != 1)
+               return false;
+
+       if (!(gi->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED))
+               return false;
+
+       /* ACPI 6.3 Table 5-80: segment + bus + devfn bytes */
+       return segment == pci_domain_nr(pdev->bus) &&
+              bus == pdev->bus->number &&
+              devfn == pdev->devfn;
+}
+
+int amdgpu_acpi_find_gpu_memory_in_srat(struct amdgpu_device *adev,
+                                       uint64_t *base_addr, uint64_t *length)
+{
+       struct acpi_srat_generic_affinity *gpu;
+       struct acpi_subtable_header *sub_header;
+       struct acpi_table_header *table_header;
+       struct acpi_srat_mem_affinity *mem;
+       struct pci_dev *pdev = adev->pdev;
+       unsigned long subtable_len;
+       unsigned long table_end;
+       acpi_status status;
+       bool pxm_found = false;
+       bool mem_found = false;
+       u64 mem_base = 0;
+       u64 mem_len = 0;
+       u32 gpu_pxm = 0;
+
+       if (!base_addr || !length)
+               return -EINVAL;
+
+       status = acpi_get_table(ACPI_SIG_SRAT, 0, &table_header);
+       if (ACPI_FAILURE(status))
+               return -ENOENT;
+
+       table_end = (unsigned long)table_header + table_header->length;
+
+       /* Pass 1: find GPU PXM from GENERIC_AFFINITY */
+       sub_header = (struct acpi_subtable_header *)
+               ((unsigned long)table_header + sizeof(struct acpi_table_srat));
+       subtable_len = sub_header->length;
+
+       while (((unsigned long)sub_header) + subtable_len <= table_end) {
+               if (subtable_len == 0)
+                       break;
+
+               if (sub_header->type == ACPI_SRAT_TYPE_GENERIC_AFFINITY) {
+                       gpu = (struct acpi_srat_generic_affinity *)sub_header;
+                       if (amdgpu_acpi_srat_pci_handle_match(pdev, gpu)) {
+                               gpu_pxm = gpu->proximity_domain;
+                               pxm_found = true;
+                               break;
+                       }
+               }
+
+               sub_header = (struct acpi_subtable_header *)
+                       ((unsigned long)sub_header + subtable_len);
+               subtable_len = sub_header->length;
+       }
+
+       if (!pxm_found) {
+               acpi_put_table(table_header);
+               dev_err(adev->dev, "SRAT: no acpi generic initiator found\n");
+               return -ENOENT;
+       }
+
+       /* Pass 2: find SPM memory for gpu_pxm */
+       sub_header = (struct acpi_subtable_header *)
+               ((unsigned long)table_header + sizeof(struct acpi_table_srat));
+       subtable_len = sub_header->length;
+
+       while (((unsigned long)sub_header) + subtable_len <= table_end) {
+               if (subtable_len == 0)
+                       break;
+
+               if (sub_header->type == ACPI_SRAT_TYPE_MEMORY_AFFINITY) {
+                       bool enabled, hotplug;
+
+                       mem = (struct acpi_srat_mem_affinity *)sub_header;
+                       enabled = mem->flags & ACPI_SRAT_MEM_ENABLED;
+                       hotplug = mem->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE;
+
+                       /* MUST filter ENABLED && !HOTPLUGGABLE */
+                       if (enabled && !hotplug &&
+                           mem->proximity_domain == gpu_pxm) {
+                               /* [mem->base_address, mem->length] is the SPM 
range */
+                               mem_base = mem->base_address;
+                               mem_len = mem->length;
+                               mem_found = true;
+                               break;
+                       }
+               }
+
+               sub_header = (struct acpi_subtable_header *)
+                       ((unsigned long)sub_header + subtable_len);
+               subtable_len = sub_header->length;
+       }
+
+       acpi_put_table(table_header);
+
+       if (!mem_found) {
+               dev_err(adev->dev, "SRAT: no memory affinity for pxm %u\n",
+                        gpu_pxm);
+               return -ENOENT;
+       }
+
+       dev_info(adev->dev, "SRAT: gpu pxm=%u base=%llx length=%llx\n",
+                gpu_pxm, mem_base, mem_len);
+
+       *base_addr = mem_base;
+       *length = mem_len;
+
+       return 0;
+}
+#else
+int amdgpu_acpi_find_gpu_memory_in_srat(struct amdgpu_device *adev,
+                                       uint64_t *base_addr, uint64_t *length)
+{
+       if (!base_addr || !length)
+               return -EINVAL;
+
+       return -ENOENT;
+}
+#endif
+
 /*
  * amdgpu_acpi_detect - detect ACPI ATIF/ATCS methods
  *
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h
index 6569a4db5dae..624faf738963 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h
@@ -102,6 +102,8 @@ int amdgpu_acpi_get_mem_info(struct amdgpu_device *adev, 
int xcc_id,
 
 void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
 bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev);
+int amdgpu_acpi_find_gpu_memory_in_srat(struct amdgpu_device *adev,
+                                       uint64_t *base_addr, uint64_t *length);
 void amdgpu_acpi_detect(void);
 void amdgpu_acpi_release(void);
 #else
@@ -117,6 +119,11 @@ static inline int amdgpu_acpi_get_mem_info(struct 
amdgpu_device *adev,
 {
        return -EINVAL;
 }
+static inline int amdgpu_acpi_find_gpu_memory_in_srat(struct amdgpu_device 
*adev,
+                                                     uint64_t *base_addr, 
uint64_t *length)
+{
+       return -EINVAL;
+}
 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
 static inline bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev) { 
return false; }
 static inline void amdgpu_acpi_detect(void) { }
-- 
2.43.0

Reply via email to