drm/amdgpu: Add parsing of acpi xcc objects
authorLijo Lazar <lijo.lazar@amd.com>
Fri, 27 Jan 2023 12:48:17 +0000 (18:18 +0530)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 9 Jun 2023 13:55:38 +0000 (09:55 -0400)
Add parsing of ACPI xcc objects and fill in relevant info from them by
invoking the DSM methods.

Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-and-tested-by: Rajneesh Bhardwaj <rajneesh.bhardwaj@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c

index 39743d4..880bf9d 100644 (file)
@@ -1404,11 +1404,13 @@ int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev);
 void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
 bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev);
 void amdgpu_acpi_detect(void);
+void amdgpu_acpi_release(void);
 #else
 static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
 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) { }
+static inline void amdgpu_acpi_release(void) { }
 static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; }
 static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev,
                                                  u8 dev_state, bool drv_state) { return 0; }
index aeeec21..a3a2ef4 100644 (file)
 #include "amd_acpi.h"
 #include "atom.h"
 
+/* Declare GUID for AMD _DSM method for XCCs */
+static const guid_t amd_xcc_dsm_guid = GUID_INIT(0x8267f5d5, 0xa556, 0x44f2,
+                                                0xb8, 0xb4, 0x45, 0x56, 0x2e,
+                                                0x8c, 0x5b, 0xec);
+
+#define AMD_XCC_HID_START 3000
+#define AMD_XCC_DSM_GET_NUM_FUNCS 0
+#define AMD_XCC_DSM_GET_SUPP_MODE 1
+#define AMD_XCC_DSM_GET_XCP_MODE 2
+#define AMD_XCC_DSM_GET_VF_XCC_MAPPING 4
+#define AMD_XCC_DSM_GET_TMR_INFO 5
+#define AMD_XCC_DSM_NUM_FUNCS 5
+
+#define AMD_XCC_MAX_HID 24
+
+/* Encapsulates the XCD acpi object information */
+struct amdgpu_acpi_xcc_info {
+       struct list_head list;
+       int mem_node;
+       uint8_t xcp_node;
+       uint8_t phy_id;
+       acpi_handle handle;
+};
+
+struct amdgpu_acpi_dev_info {
+       struct list_head list;
+       struct list_head xcc_list;
+       uint16_t bdf;
+       uint16_t supp_xcp_mode;
+       uint16_t xcp_mode;
+       uint16_t mem_mode;
+       uint64_t tmr_base;
+       uint64_t tmr_size;
+};
+
+struct list_head amdgpu_acpi_dev_list;
+
 struct amdgpu_atif_notification_cfg {
        bool enabled;
        int command_code;
@@ -802,6 +839,240 @@ int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_sta
 }
 
 /**
+ * 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
+ *
+ * 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)
+{
+#ifdef CONFIG_ACPI_NUMA
+       u64 pxm;
+       acpi_status status;
+
+       status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       *nid = pxm_to_node(pxm);
+
+       return_ACPI_STATUS(AE_OK);
+#else
+       return_ACPI_STATUS(AE_NOT_EXIST);
+#endif
+}
+
+struct amdgpu_acpi_dev_info *amdgpu_acpi_get_dev(u16 bdf)
+{
+       struct amdgpu_acpi_dev_info *acpi_dev;
+
+       if (list_empty(&amdgpu_acpi_dev_list))
+               return NULL;
+
+       list_for_each_entry(acpi_dev, &amdgpu_acpi_dev_list, list)
+               if (acpi_dev->bdf == bdf)
+                       return acpi_dev;
+
+       return NULL;
+}
+
+static int amdgpu_acpi_dev_init(struct amdgpu_acpi_dev_info **dev_info,
+                               struct amdgpu_acpi_xcc_info *xcc_info, u16 bdf)
+{
+       struct amdgpu_acpi_dev_info *tmp;
+       union acpi_object *obj;
+       int ret = -ENOENT;
+
+       *dev_info = NULL;
+       tmp = kzalloc(sizeof(struct amdgpu_acpi_dev_info), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&tmp->xcc_list);
+       INIT_LIST_HEAD(&tmp->list);
+       tmp->bdf = bdf;
+
+       obj = acpi_evaluate_dsm_typed(xcc_info->handle, &amd_xcc_dsm_guid, 0,
+                                     AMD_XCC_DSM_GET_SUPP_MODE, NULL,
+                                     ACPI_TYPE_INTEGER);
+
+       if (!obj) {
+               acpi_handle_debug(xcc_info->handle,
+                                 "_DSM function %d evaluation failed",
+                                 AMD_XCC_DSM_GET_SUPP_MODE);
+               ret = -ENOENT;
+               goto out;
+       }
+
+       tmp->supp_xcp_mode = obj->integer.value & 0xFFFF;
+       ACPI_FREE(obj);
+
+       obj = acpi_evaluate_dsm_typed(xcc_info->handle, &amd_xcc_dsm_guid, 0,
+                                     AMD_XCC_DSM_GET_XCP_MODE, NULL,
+                                     ACPI_TYPE_INTEGER);
+
+       if (!obj) {
+               acpi_handle_debug(xcc_info->handle,
+                                 "_DSM function %d evaluation failed",
+                                 AMD_XCC_DSM_GET_XCP_MODE);
+               ret = -ENOENT;
+               goto out;
+       }
+
+       tmp->xcp_mode = obj->integer.value & 0xFFFF;
+       tmp->mem_mode = (obj->integer.value >> 32) & 0xFFFF;
+       ACPI_FREE(obj);
+
+       /* Evaluate DSMs and fill XCC information */
+       obj = acpi_evaluate_dsm_typed(xcc_info->handle, &amd_xcc_dsm_guid, 0,
+                                     AMD_XCC_DSM_GET_TMR_INFO, NULL,
+                                     ACPI_TYPE_PACKAGE);
+
+       if (!obj || obj->package.count < 2) {
+               acpi_handle_debug(xcc_info->handle,
+                                 "_DSM function %d evaluation failed",
+                                 AMD_XCC_DSM_GET_TMR_INFO);
+               ret = -ENOENT;
+               goto out;
+       }
+
+       tmp->tmr_base = obj->package.elements[0].integer.value;
+       tmp->tmr_size = obj->package.elements[1].integer.value;
+       ACPI_FREE(obj);
+
+       DRM_DEBUG_DRIVER(
+               "New dev(%x): Supported xcp mode: %x curr xcp_mode : %x mem mode : %x, tmr base: %llx tmr size: %llx  ",
+               tmp->bdf, tmp->supp_xcp_mode, tmp->xcp_mode, tmp->mem_mode,
+               tmp->tmr_base, tmp->tmr_size);
+       list_add_tail(&tmp->list, &amdgpu_acpi_dev_list);
+       *dev_info = tmp;
+
+       return 0;
+
+out:
+       if (obj)
+               ACPI_FREE(obj);
+       kfree(tmp);
+
+       return ret;
+}
+
+static int amdgpu_acpi_get_xcc_info(struct amdgpu_acpi_xcc_info *xcc_info,
+                                   u16 *bdf)
+{
+       union acpi_object *obj;
+       acpi_status status;
+       int ret = -ENOENT;
+
+       obj = acpi_evaluate_dsm_typed(xcc_info->handle, &amd_xcc_dsm_guid, 0,
+                                     AMD_XCC_DSM_GET_NUM_FUNCS, NULL,
+                                     ACPI_TYPE_INTEGER);
+
+       if (!obj || obj->integer.value != AMD_XCC_DSM_NUM_FUNCS)
+               goto out;
+       ACPI_FREE(obj);
+
+       /* Evaluate DSMs and fill XCC information */
+       obj = acpi_evaluate_dsm_typed(xcc_info->handle, &amd_xcc_dsm_guid, 0,
+                                     AMD_XCC_DSM_GET_VF_XCC_MAPPING, NULL,
+                                     ACPI_TYPE_INTEGER);
+
+       if (!obj) {
+               acpi_handle_debug(xcc_info->handle,
+                                 "_DSM function %d evaluation failed",
+                                 AMD_XCC_DSM_GET_VF_XCC_MAPPING);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* PF xcc id [39:32] */
+       xcc_info->phy_id = (obj->integer.value >> 32) & 0xFF;
+       /* xcp node of this xcc [47:40] */
+       xcc_info->xcp_node = (obj->integer.value >> 40) & 0xFF;
+       /* PF bus/dev/fn of this xcc [63:48] */
+       *bdf = (obj->integer.value >> 48) & 0xFFFF;
+       ACPI_FREE(obj);
+       obj = NULL;
+
+       status = amdgpu_acpi_get_node_id(xcc_info->handle, &xcc_info->mem_node);
+
+       /* TODO: check if this check is required */
+       if (ACPI_SUCCESS(status))
+               ret = 0;
+out:
+       if (obj)
+               ACPI_FREE(obj);
+
+       return ret;
+}
+
+static int amdgpu_acpi_enumerate_xcc(void)
+{
+       struct amdgpu_acpi_dev_info *dev_info = NULL;
+       struct amdgpu_acpi_xcc_info *xcc_info;
+       struct acpi_device *acpi_dev;
+       char hid[ACPI_ID_LEN];
+       int ret, id;
+       u16 bdf;
+
+       INIT_LIST_HEAD(&amdgpu_acpi_dev_list);
+
+       for (id = 0; id < AMD_XCC_MAX_HID; id++) {
+               sprintf(hid, "%s%d", "AMD", AMD_XCC_HID_START + id);
+               acpi_dev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+               /* These ACPI objects are expected to be in sequential order. If
+                * one is not found, no need to check the rest.
+                */
+               if (!acpi_dev) {
+                       DRM_DEBUG_DRIVER("No matching acpi device found for %s",
+                                        hid);
+                       break;
+               }
+
+               xcc_info = kzalloc(sizeof(struct amdgpu_acpi_xcc_info),
+                                  GFP_KERNEL);
+               if (!xcc_info) {
+                       DRM_ERROR("Failed to allocate memory for xcc info\n");
+                       return -ENOMEM;
+               }
+
+               INIT_LIST_HEAD(&xcc_info->list);
+               xcc_info->handle = acpi_device_handle(acpi_dev);
+               acpi_dev_put(acpi_dev);
+
+               ret = amdgpu_acpi_get_xcc_info(xcc_info, &bdf);
+               if (ret) {
+                       kfree(xcc_info);
+                       continue;
+               }
+
+               dev_info = amdgpu_acpi_get_dev(bdf);
+
+               if (!dev_info)
+                       ret = amdgpu_acpi_dev_init(&dev_info, xcc_info, bdf);
+
+               if (ret == -ENOMEM)
+                       return ret;
+
+               if (!dev_info) {
+                       kfree(xcc_info);
+                       continue;
+               }
+
+               list_add_tail(&xcc_info->list, &dev_info->xcc_list);
+       }
+
+       return 0;
+}
+
+/**
  * amdgpu_acpi_event - handle notify events
  *
  * @nb: notifier block
@@ -1054,6 +1325,29 @@ void amdgpu_acpi_detect(void)
        } else {
                atif->backlight_caps.caps_valid = false;
        }
+
+       amdgpu_acpi_enumerate_xcc();
+}
+
+void amdgpu_acpi_release(void)
+{
+       struct amdgpu_acpi_dev_info *dev_info, *dev_tmp;
+       struct amdgpu_acpi_xcc_info *xcc_info, *xcc_tmp;
+
+       if (list_empty(&amdgpu_acpi_dev_list))
+               return;
+
+       list_for_each_entry_safe(dev_info, dev_tmp, &amdgpu_acpi_dev_list,
+                                list) {
+               list_for_each_entry_safe(xcc_info, xcc_tmp, &dev_info->xcc_list,
+                                        list) {
+                       list_del(&xcc_info->list);
+                       kfree(xcc_info);
+               }
+
+               list_del(&dev_info->list);
+               kfree(dev_info);
+       }
 }
 
 #if IS_ENABLED(CONFIG_SUSPEND)
index 9e9da2a..f319318 100644 (file)
@@ -2898,6 +2898,7 @@ static void __exit amdgpu_exit(void)
        amdgpu_amdkfd_fini();
        pci_unregister_driver(&amdgpu_kms_pci_driver);
        amdgpu_unregister_atpx_handler();
+       amdgpu_acpi_release();
        amdgpu_sync_fini();
        amdgpu_fence_slab_fini();
        mmu_notifier_synchronize();