]> Git Repo - linux.git/blobdiff - drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[linux.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_acpi.c
index 9dbdd699dcea6e2d9f4154c86c5f9748aa3bfccb..385c6acb5728b7406f6211b3dab9166f1e48914a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/acpi.h>
 #include <linux/backlight.h>
 #include <linux/slab.h>
+#include <linux/xarray.h>
 #include <linux/power_supply.h>
 #include <linux/pm_runtime.h>
 #include <linux/suspend.h>
@@ -53,10 +54,12 @@ static const guid_t amd_xcc_dsm_guid = GUID_INIT(0x8267f5d5, 0xa556, 0x44f2,
 
 #define AMD_XCC_MAX_HID 24
 
+struct xarray numa_info_xa;
+
 /* Encapsulates the XCD acpi object information */
 struct amdgpu_acpi_xcc_info {
        struct list_head list;
-       int mem_node;
+       struct amdgpu_numa_info *numa_info;
        uint8_t xcp_node;
        uint8_t phy_id;
        acpi_handle handle;
@@ -838,30 +841,85 @@ int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_sta
        return r;
 }
 
+#ifdef CONFIG_ACPI_NUMA
+static inline uint64_t amdgpu_acpi_get_numa_size(int nid)
+{
+       /* This is directly using si_meminfo_node implementation as the
+        * function is not exported.
+        */
+       int zone_type;
+       uint64_t managed_pages = 0;
+
+       pg_data_t *pgdat = NODE_DATA(nid);
+
+       for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++)
+               managed_pages +=
+                       zone_managed_pages(&pgdat->node_zones[zone_type]);
+       return managed_pages * PAGE_SIZE;
+}
+
+static struct amdgpu_numa_info *amdgpu_acpi_get_numa_info(uint32_t pxm)
+{
+       struct amdgpu_numa_info *numa_info;
+       int nid;
+
+       numa_info = xa_load(&numa_info_xa, pxm);
+
+       if (!numa_info) {
+               struct sysinfo info;
+
+               numa_info = kzalloc(sizeof *numa_info, GFP_KERNEL);
+               if (!numa_info)
+                       return NULL;
+
+               nid = pxm_to_node(pxm);
+               numa_info->pxm = pxm;
+               numa_info->nid = nid;
+
+               if (numa_info->nid == NUMA_NO_NODE) {
+                       si_meminfo(&info);
+                       numa_info->size = info.totalram * info.mem_unit;
+               } else {
+                       numa_info->size = amdgpu_acpi_get_numa_size(nid);
+               }
+               xa_store(&numa_info_xa, numa_info->pxm, numa_info, GFP_KERNEL);
+       }
+
+       return numa_info;
+}
+#endif
+
 /**
  * amdgpu_acpi_get_node_id - obtain the NUMA node id for corresponding amdgpu
  * acpi device handle
  *
  * @handle: acpi handle
- * @nid: NUMA Node id returned by the platform firmware
+ * @numa_info: amdgpu_numa_info structure holding numa information
  *
  * Queries the ACPI interface to fetch the corresponding NUMA Node ID for a
  * given amdgpu acpi device.
  *
  * Returns ACPI STATUS OK with Node ID on success or the corresponding failure reason
  */
-acpi_status amdgpu_acpi_get_node_id(acpi_handle handle, int *nid)
+static acpi_status amdgpu_acpi_get_node_id(acpi_handle handle,
+                                   struct amdgpu_numa_info **numa_info)
 {
 #ifdef CONFIG_ACPI_NUMA
        u64 pxm;
        acpi_status status;
 
+       if (!numa_info)
+               return_ACPI_STATUS(AE_ERROR);
+
        status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
 
        if (ACPI_FAILURE(status))
                return status;
 
-       *nid = pxm_to_node(pxm);
+       *numa_info = amdgpu_acpi_get_numa_info(pxm);
+
+       if (!*numa_info)
+               return_ACPI_STATUS(AE_ERROR);
 
        return_ACPI_STATUS(AE_OK);
 #else
@@ -869,7 +927,7 @@ acpi_status amdgpu_acpi_get_node_id(acpi_handle handle, int *nid)
 #endif
 }
 
-struct amdgpu_acpi_dev_info *amdgpu_acpi_get_dev(u16 bdf)
+static struct amdgpu_acpi_dev_info *amdgpu_acpi_get_dev(u16 bdf)
 {
        struct amdgpu_acpi_dev_info *acpi_dev;
 
@@ -1001,7 +1059,8 @@ static int amdgpu_acpi_get_xcc_info(struct amdgpu_acpi_xcc_info *xcc_info,
        ACPI_FREE(obj);
        obj = NULL;
 
-       status = amdgpu_acpi_get_node_id(xcc_info->handle, &xcc_info->mem_node);
+       status =
+               amdgpu_acpi_get_node_id(xcc_info->handle, &xcc_info->numa_info);
 
        /* TODO: check if this check is required */
        if (ACPI_SUCCESS(status))
@@ -1023,6 +1082,7 @@ static int amdgpu_acpi_enumerate_xcc(void)
        u16 bdf;
 
        INIT_LIST_HEAD(&amdgpu_acpi_dev_list);
+       xa_init(&numa_info_xa);
 
        for (id = 0; id < AMD_XCC_MAX_HID; id++) {
                sprintf(hid, "%s%d", "AMD", AMD_XCC_HID_START + id);
@@ -1092,6 +1152,32 @@ int amdgpu_acpi_get_tmr_info(struct amdgpu_device *adev, u64 *tmr_offset,
        return 0;
 }
 
+int amdgpu_acpi_get_mem_info(struct amdgpu_device *adev, int xcc_id,
+                            struct amdgpu_numa_info *numa_info)
+{
+       struct amdgpu_acpi_dev_info *dev_info;
+       struct amdgpu_acpi_xcc_info *xcc_info;
+       u16 bdf;
+
+       if (!numa_info)
+               return -EINVAL;
+
+       bdf = (adev->pdev->bus->number << 8) | adev->pdev->devfn;
+       dev_info = amdgpu_acpi_get_dev(bdf);
+       if (!dev_info)
+               return -ENOENT;
+
+       list_for_each_entry(xcc_info, &dev_info->xcc_list, list) {
+               if (xcc_info->phy_id == xcc_id) {
+                       memcpy(numa_info, xcc_info->numa_info,
+                              sizeof(*numa_info));
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
 /**
  * amdgpu_acpi_event - handle notify events
  *
@@ -1353,6 +1439,13 @@ void amdgpu_acpi_release(void)
 {
        struct amdgpu_acpi_dev_info *dev_info, *dev_tmp;
        struct amdgpu_acpi_xcc_info *xcc_info, *xcc_tmp;
+       struct amdgpu_numa_info *numa_info;
+       unsigned long index;
+
+       xa_for_each(&numa_info_xa, index, numa_info) {
+               kfree(numa_info);
+               xa_erase(&numa_info_xa, index);
+       }
 
        if (list_empty(&amdgpu_acpi_dev_list))
                return;
@@ -1406,16 +1499,20 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
         * S0ix even though the system is suspending to idle, so return false
         * in that case.
         */
-       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
-               dev_warn_once(adev->dev,
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
+               dev_err_once(adev->dev,
                              "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n"
                              "To use suspend-to-idle change the sleep mode in BIOS setup.\n");
+               return false;
+       }
 
 #if !IS_ENABLED(CONFIG_AMD_PMC)
-       dev_warn_once(adev->dev,
+       dev_err_once(adev->dev,
                      "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n");
-#endif /* CONFIG_AMD_PMC */
+       return false;
+#else
        return true;
+#endif /* CONFIG_AMD_PMC */
 }
 
 #endif /* CONFIG_SUSPEND */
This page took 0.04264 seconds and 4 git commands to generate.