From: Likun Gao <[email protected]>

Add sysfs interface to copy VBIOS.

Signed-off-by: Andrey Grodzovsky <[email protected]>
Signed-off-by: Likun Gao <[email protected]>
Reviewed-by: Hawking Zhang <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h        |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |  10 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 117 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |   6 ++
 4 files changed, 134 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 058f272e40ee..3c20c2eadf4e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1013,6 +1013,7 @@ struct amdgpu_device {
 
        bool                            pm_sysfs_en;
        bool                            ucode_sysfs_en;
+       bool                            psp_sysfs_en;
 
        /* Chip product information */
        char                            product_number[16];
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index b07f295a449e..b583026dc893 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3868,6 +3868,14 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        } else
                adev->ucode_sysfs_en = true;
 
+       r = amdgpu_psp_sysfs_init(adev);
+       if (r) {
+               adev->psp_sysfs_en = false;
+               if (!amdgpu_sriov_vf(adev))
+                       DRM_ERROR("Creating psp sysfs failed\n");
+       } else
+               adev->psp_sysfs_en = true;
+
        /*
         * Register gpu instance before amdgpu_device_enable_mgpu_fan_boost.
         * Otherwise the mgpu fan boost feature will be skipped due to the
@@ -4000,6 +4008,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
                amdgpu_pm_sysfs_fini(adev);
        if (adev->ucode_sysfs_en)
                amdgpu_ucode_sysfs_fini(adev);
+       if (adev->psp_sysfs_en)
+               amdgpu_psp_sysfs_fini(adev);
        sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes);
 
        /* disable ras feature must before hw fini */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 25c90ad2c0b7..7d0a37a94ea6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -42,6 +42,8 @@
 #include "amdgpu_securedisplay.h"
 #include "amdgpu_atomfirmware.h"
 
+#define AMD_VBIOS_FILE_MAX_SIZE_B      (1024*1024*3)
+
 static int psp_sysfs_init(struct amdgpu_device *adev);
 static void psp_sysfs_fini(struct amdgpu_device *adev);
 
@@ -3443,6 +3445,116 @@ int is_psp_fw_valid(struct psp_bin_desc bin)
        return bin.size_bytes;
 }
 
+static ssize_t amdgpu_psp_vbflash_write(struct file *filp, struct kobject 
*kobj,
+                                       struct bin_attribute *bin_attr,
+                                       char *buffer, loff_t pos, size_t count)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(ddev);
+
+       /* Safeguard against memory drain */
+       if (adev->psp.vbflash_image_size > AMD_VBIOS_FILE_MAX_SIZE_B) {
+               dev_err(adev->dev, "File size cannot exceed %u", 
AMD_VBIOS_FILE_MAX_SIZE_B);
+               vfree(adev->psp.vbflash_tmp_buf);
+               adev->psp.vbflash_tmp_buf = NULL;
+               adev->psp.vbflash_image_size = 0;
+               return -ENOMEM;
+       }
+
+       /* TODO Just allocate max for now and optimize to realloc later if 
needed */
+       if (!adev->psp.vbflash_tmp_buf) {
+               adev->psp.vbflash_tmp_buf = vmalloc(AMD_VBIOS_FILE_MAX_SIZE_B);
+               if (!adev->psp.vbflash_tmp_buf)
+                       return -ENOMEM;
+       }
+
+       mutex_lock(&adev->psp.mutex);
+       memcpy(adev->psp.vbflash_tmp_buf + pos, buffer, count);
+       adev->psp.vbflash_image_size += count;
+       mutex_unlock(&adev->psp.mutex);
+
+       dev_info(adev->dev, "VBIOS flash write PSP done");
+
+       return count;
+}
+
+static ssize_t amdgpu_psp_vbflash_read(struct file *filp, struct kobject *kobj,
+                                      struct bin_attribute *bin_attr, char 
*buffer,
+                                      loff_t pos, size_t count)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(ddev);
+       struct amdgpu_bo *fw_buf_bo = NULL;
+       uint64_t fw_pri_mc_addr;
+       void *fw_pri_cpu_addr;
+       int ret;
+
+       dev_info(adev->dev, "VBIOS flash to PSP started");
+
+       ret = amdgpu_bo_create_kernel(adev, adev->psp.vbflash_image_size,
+                                       AMDGPU_GPU_PAGE_SIZE,
+                                       AMDGPU_GEM_DOMAIN_VRAM,
+                                       &fw_buf_bo,
+                                       &fw_pri_mc_addr,
+                                       &fw_pri_cpu_addr);
+       if (ret)
+               goto rel_buf;
+
+       memcpy_toio(fw_pri_cpu_addr, adev->psp.vbflash_tmp_buf, 
adev->psp.vbflash_image_size);
+
+       mutex_lock(&adev->psp.mutex);
+       ret = psp_update_spirom(&adev->psp, fw_pri_mc_addr);
+       mutex_unlock(&adev->psp.mutex);
+
+       amdgpu_bo_free_kernel(&fw_buf_bo, &fw_pri_mc_addr, &fw_pri_cpu_addr);
+
+rel_buf:
+       vfree(adev->psp.vbflash_tmp_buf);
+       adev->psp.vbflash_tmp_buf = NULL;
+       adev->psp.vbflash_image_size = 0;
+
+       if (ret) {
+               dev_err(adev->dev, "Failed to load VBIOS FW, err = %d", ret);
+               return ret;
+       }
+
+       dev_info(adev->dev, "VBIOS flash to PSP done");
+       return 0;
+}
+
+static const struct bin_attribute psp_vbflash_bin_attr = {
+       .attr = {.name = "psp_vbflash", .mode = 0664},
+       .size = 0,
+       .write = amdgpu_psp_vbflash_write,
+       .read = amdgpu_psp_vbflash_read,
+};
+
+int amdgpu_psp_sysfs_init(struct amdgpu_device *adev)
+{
+       int ret = 0;
+       struct psp_context *psp = &adev->psp;
+
+       if (amdgpu_sriov_vf(adev))
+               return -EINVAL;
+
+       switch (adev->ip_versions[MP0_HWIP][0]) {
+       case IP_VERSION(13, 0, 0):
+       case IP_VERSION(13, 0, 7):
+               if (!psp->adev) {
+                       psp->adev = adev;
+                       psp_v13_0_set_psp_funcs(psp);
+               }
+               ret = sysfs_create_bin_file(&adev->dev->kobj, 
&psp_vbflash_bin_attr);
+               if (ret)
+                       dev_err(adev->dev, "Failed to create device file 
psp_vbflash");
+               return ret;
+       default:
+               return 0;
+       }
+}
+
 const struct amd_ip_funcs psp_ip_funcs = {
        .name = "psp",
        .early_init = psp_early_init,
@@ -3471,6 +3583,11 @@ static int psp_sysfs_init(struct amdgpu_device *adev)
        return ret;
 }
 
+void amdgpu_psp_sysfs_fini(struct amdgpu_device *adev)
+{
+       sysfs_remove_bin_file(&adev->dev->kobj, &psp_vbflash_bin_attr);
+}
+
 static void psp_sysfs_fini(struct amdgpu_device *adev)
 {
        device_remove_file(adev->dev, &dev_attr_usbc_pd_fw);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
index 81ecbdeb1ddb..db7b7dbb9c93 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
@@ -372,6 +372,9 @@ struct psp_context
        struct psp_memory_training_context mem_train_ctx;
 
        uint32_t                        boot_cfg_bitmask;
+
+       char *vbflash_tmp_buf;
+       size_t vbflash_image_size;
 };
 
 struct amdgpu_psp_funcs {
@@ -501,4 +504,7 @@ int psp_load_fw_list(struct psp_context *psp,
 void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t 
bin_size);
 
 int is_psp_fw_valid(struct psp_bin_desc bin);
+
+int amdgpu_psp_sysfs_init(struct amdgpu_device *adev);
+void amdgpu_psp_sysfs_fini(struct amdgpu_device *adev);
 #endif
-- 
2.35.1

Reply via email to