Commit 0ad7347a authored by André Almeida's avatar André Almeida Committed by Alex Deucher
Browse files

drm/amd: Add detailed GFXOFF stats to debugfs



Add debugfs interface to log GFXOFF statistics:

- Read amdgpu_gfxoff_count to get the total GFXOFF entry count at the
  time of query since system power-up

- Write 1 to amdgpu_gfxoff_residency to start logging, and 0 to stop.
  Read it to get average GFXOFF residency % multiplied by 100
  during the last logging interval.

Both features are designed to be keep the values persistent between
suspends.

Signed-off-by: default avatarAndré Almeida <andrealmeid@igalia.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 30f2d2e4
Loading
Loading
Loading
Loading
+168 −0
Original line number Diff line number Diff line
@@ -1042,6 +1042,157 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
	return r;
}

/**
 * amdgpu_debugfs_gfxoff_residency_read - Read GFXOFF residency
 *
 * @f: open file handle
 * @buf: User buffer to store read data in
 * @size: Number of bytes to read
 * @pos:  Offset to seek to
 *
 * Read the last residency value logged. It doesn't auto update, one needs to
 * stop logging before getting the current value.
 */
static ssize_t amdgpu_debugfs_gfxoff_residency_read(struct file *f, char __user *buf,
						    size_t size, loff_t *pos)
{
	struct amdgpu_device *adev = file_inode(f)->i_private;
	ssize_t result = 0;
	int r;

	if (size & 0x3 || *pos & 0x3)
		return -EINVAL;

	r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
	if (r < 0) {
		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
		return r;
	}

	while (size) {
		uint32_t value;

		r = amdgpu_get_gfx_off_residency(adev, &value);
		if (r)
			goto out;

		r = put_user(value, (uint32_t *)buf);
		if (r)
			goto out;

		result += 4;
		buf += 4;
		*pos += 4;
		size -= 4;
	}

	r = result;
out:
	pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);

	return r;
}

/**
 * amdgpu_debugfs_gfxoff_residency_write - Log GFXOFF Residency
 *
 * @f: open file handle
 * @buf: User buffer to write data from
 * @size: Number of bytes to write
 * @pos:  Offset to seek to
 *
 * Write a 32-bit non-zero to start logging; write a 32-bit zero to stop
 */
static ssize_t amdgpu_debugfs_gfxoff_residency_write(struct file *f, const char __user *buf,
						     size_t size, loff_t *pos)
{
	struct amdgpu_device *adev = file_inode(f)->i_private;
	ssize_t result = 0;
	int r;

	if (size & 0x3 || *pos & 0x3)
		return -EINVAL;

	r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
	if (r < 0) {
		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
		return r;
	}

	while (size) {
		u32 value;

		r = get_user(value, (uint32_t *)buf);
		if (r)
			goto out;

		amdgpu_set_gfx_off_residency(adev, value ? true : false);

		result += 4;
		buf += 4;
		*pos += 4;
		size -= 4;
	}

	r = result;
out:
	pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);

	return r;
}


/**
 * amdgpu_debugfs_gfxoff_count_read - Read GFXOFF entry count
 *
 * @f: open file handle
 * @buf: User buffer to store read data in
 * @size: Number of bytes to read
 * @pos:  Offset to seek to
 */
static ssize_t amdgpu_debugfs_gfxoff_count_read(struct file *f, char __user *buf,
						size_t size, loff_t *pos)
{
	struct amdgpu_device *adev = file_inode(f)->i_private;
	ssize_t result = 0;
	int r;

	if (size & 0x3 || *pos & 0x3)
		return -EINVAL;

	r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
	if (r < 0) {
		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
		return r;
	}

	while (size) {
		u64 value = 0;

		r = amdgpu_get_gfx_off_entrycount(adev, &value);
		if (r)
			goto out;

		r = put_user(value, (u64 *)buf);
		if (r)
			goto out;

		result += 4;
		buf += 4;
		*pos += 4;
		size -= 4;
	}

	r = result;
out:
	pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);

	return r;
}

/**
 * amdgpu_debugfs_gfxoff_write - Enable/disable GFXOFF
 *
@@ -1249,6 +1400,19 @@ static const struct file_operations amdgpu_debugfs_gfxoff_status_fops = {
	.llseek = default_llseek
};

static const struct file_operations amdgpu_debugfs_gfxoff_count_fops = {
	.owner = THIS_MODULE,
	.read = amdgpu_debugfs_gfxoff_count_read,
	.llseek = default_llseek
};

static const struct file_operations amdgpu_debugfs_gfxoff_residency_fops = {
	.owner = THIS_MODULE,
	.read = amdgpu_debugfs_gfxoff_residency_read,
	.write = amdgpu_debugfs_gfxoff_residency_write,
	.llseek = default_llseek
};

static const struct file_operations *debugfs_regs[] = {
	&amdgpu_debugfs_regs_fops,
	&amdgpu_debugfs_regs2_fops,
@@ -1261,6 +1425,8 @@ static const struct file_operations *debugfs_regs[] = {
	&amdgpu_debugfs_gpr_fops,
	&amdgpu_debugfs_gfxoff_fops,
	&amdgpu_debugfs_gfxoff_status_fops,
	&amdgpu_debugfs_gfxoff_count_fops,
	&amdgpu_debugfs_gfxoff_residency_fops,
};

static const char *debugfs_regs_names[] = {
@@ -1275,6 +1441,8 @@ static const char *debugfs_regs_names[] = {
	"amdgpu_gpr",
	"amdgpu_gfxoff",
	"amdgpu_gfxoff_status",
	"amdgpu_gfxoff_count",
	"amdgpu_gfxoff_residency",
};

/**
+2 −0
Original line number Diff line number Diff line
@@ -3577,6 +3577,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
	INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func);

	adev->gfx.gfx_off_req_count = 1;
	adev->gfx.gfx_off_residency = 0;
	adev->gfx.gfx_off_entrycount = 0;
	adev->pm.ac_power = power_supply_is_system_supplied() > 0;

	atomic_set(&adev->throttling_logging_enabled, 1);
+39 −0
Original line number Diff line number Diff line
@@ -610,6 +610,45 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
	mutex_unlock(&adev->gfx.gfx_off_mutex);
}

int amdgpu_set_gfx_off_residency(struct amdgpu_device *adev, bool value)
{
	int r = 0;

	mutex_lock(&adev->gfx.gfx_off_mutex);

	r = amdgpu_dpm_set_residency_gfxoff(adev, value);

	mutex_unlock(&adev->gfx.gfx_off_mutex);

	return r;
}

int amdgpu_get_gfx_off_residency(struct amdgpu_device *adev, u32 *value)
{
	int r = 0;

	mutex_lock(&adev->gfx.gfx_off_mutex);

	r = amdgpu_dpm_get_residency_gfxoff(adev, value);

	mutex_unlock(&adev->gfx.gfx_off_mutex);

	return r;
}

int amdgpu_get_gfx_off_entrycount(struct amdgpu_device *adev, u64 *value)
{
	int r = 0;

	mutex_lock(&adev->gfx.gfx_off_mutex);

	r = amdgpu_dpm_get_entrycount_gfxoff(adev, value);

	mutex_unlock(&adev->gfx.gfx_off_mutex);

	return r;
}

int amdgpu_get_gfx_off_status(struct amdgpu_device *adev, uint32_t *value)
{

+6 −0
Original line number Diff line number Diff line
@@ -336,6 +336,8 @@ struct amdgpu_gfx {
	struct mutex                    gfx_off_mutex;
	uint32_t                        gfx_off_req_count; /* default 1, enable gfx off: dec 1, disable gfx off: add 1 */
	struct delayed_work             gfx_off_delay_work;
	uint32_t                        gfx_off_residency;
	uint64_t                        gfx_off_entrycount;

	/* pipe reservation */
	struct mutex			pipe_reserve_mutex;
@@ -407,6 +409,10 @@ bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me,
void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable);
int amdgpu_get_gfx_off_status(struct amdgpu_device *adev, uint32_t *value);
int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block);
void amdgpu_gfx_ras_fini(struct amdgpu_device *adev);
int amdgpu_get_gfx_off_entrycount(struct amdgpu_device *adev, u64 *value);
int amdgpu_get_gfx_off_residency(struct amdgpu_device *adev, u32 *residency);
int amdgpu_set_gfx_off_residency(struct amdgpu_device *adev, bool value);
int amdgpu_gfx_process_ras_data_cb(struct amdgpu_device *adev,
		void *err_data,
		struct amdgpu_iv_entry *entry);
+45 −0
Original line number Diff line number Diff line
@@ -668,6 +668,51 @@ int amdgpu_dpm_wait_for_event(struct amdgpu_device *adev,
	return ret;
}

int amdgpu_dpm_set_residency_gfxoff(struct amdgpu_device *adev, bool value)
{
	struct smu_context *smu = adev->powerplay.pp_handle;
	int ret = 0;

	if (!is_support_sw_smu(adev))
		return -EOPNOTSUPP;

	mutex_lock(&adev->pm.mutex);
	ret = smu_set_residency_gfxoff(smu, value);
	mutex_unlock(&adev->pm.mutex);

	return ret;
}

int amdgpu_dpm_get_residency_gfxoff(struct amdgpu_device *adev, u32 *value)
{
	struct smu_context *smu = adev->powerplay.pp_handle;
	int ret = 0;

	if (!is_support_sw_smu(adev))
		return -EOPNOTSUPP;

	mutex_lock(&adev->pm.mutex);
	ret = smu_get_residency_gfxoff(smu, value);
	mutex_unlock(&adev->pm.mutex);

	return ret;
}

int amdgpu_dpm_get_entrycount_gfxoff(struct amdgpu_device *adev, u64 *value)
{
	struct smu_context *smu = adev->powerplay.pp_handle;
	int ret = 0;

	if (!is_support_sw_smu(adev))
		return -EOPNOTSUPP;

	mutex_lock(&adev->pm.mutex);
	ret = smu_get_entrycount_gfxoff(smu, value);
	mutex_unlock(&adev->pm.mutex);

	return ret;
}

int amdgpu_dpm_get_status_gfxoff(struct amdgpu_device *adev, uint32_t *value)
{
	struct smu_context *smu = adev->powerplay.pp_handle;
Loading