drm/amdgpu/psp: Add vbflash sysfs interface support

Add sysfs interface to copy VBIOS.

v2: squash in fix for proper vmalloc API (Alex)

Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
Signed-off-by: Likun Gao <Likun.Gao@amd.com>
Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Likun Gao 2022-02-22 13:34:28 +08:00 committed by Alex Deucher
parent 09fffcd969
commit 8424f2ccb3
4 changed files with 134 additions and 0 deletions

View File

@ -1008,6 +1008,7 @@ struct amdgpu_device {
bool pm_sysfs_en;
bool ucode_sysfs_en;
bool psp_sysfs_en;
/* Chip product information */
char product_number[16];

View File

@ -3869,6 +3869,14 @@ fence_driver_init:
} 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
@ -4001,6 +4009,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 */

View File

@ -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);
kvfree(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 = kvmalloc(AMD_VBIOS_FILE_MAX_SIZE_B, GFP_KERNEL);
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:
kvfree(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);

View File

@ -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