Commit 8424f2cc authored by Likun Gao's avatar Likun Gao Committed by Alex Deucher
Browse files

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: default avatarAndrey Grodzovsky <andrey.grodzovsky@amd.com>
Signed-off-by: default avatarLikun Gao <Likun.Gao@amd.com>
Reviewed-by: default avatarHawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 09fffcd9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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];
+10 −0
Original line number Diff line number Diff line
@@ -3869,6 +3869,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
@@ -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 */
+117 −0
Original line number Diff line number Diff line
@@ -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);
+6 −0
Original line number Diff line number Diff line
@@ -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