All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
@ 2021-08-25 17:26 Tom St Denis
  2021-08-26  9:59 ` Christian König
  2021-08-26 12:12 ` Lazar, Lijo
  0 siblings, 2 replies; 9+ messages in thread
From: Tom St Denis @ 2021-08-25 17:26 UTC (permalink / raw)
  To: amd-gfx; +Cc: Tom St Denis

This new debugfs interface uses an IOCTL interface in order to pass
along state information like SRBM and GRBM bank switching.  This
new interface also allows a full 32-bit MMIO address range which
the previous didn't.  With this new design we have room to grow
the flexibility of the file as need be.

(v2): Move read/write to .read/.write, fix style, add comment
      for IOCTL data structure

(v3): C style comments

(v4): use u32 in struct and remove offset variable

(v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
      instead of 0x3FF, use mutex for op/ioctl.

Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
 3 files changed, 201 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index 277128846dd1..87766fef0b1c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -36,6 +36,7 @@
 #include "amdgpu_rap.h"
 #include "amdgpu_securedisplay.h"
 #include "amdgpu_fw_attestation.h"
+#include "amdgpu_umr.h"
 
 int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
 {
@@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
 	return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
 }
 
+static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
+{
+	struct amdgpu_debugfs_regs2_data *rd;
+
+	rd = kzalloc(sizeof *rd, GFP_KERNEL);
+	if (!rd)
+		return -ENOMEM;
+	rd->adev = file_inode(file)->i_private;
+	file->private_data = rd;
+	mutex_init(&rd->lock);
+
+	return 0;
+}
+
+static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
+{
+	struct amdgpu_debugfs_regs2_data *rd = f->private_data;
+	struct amdgpu_device *adev = rd->adev;
+	ssize_t result = 0;
+	int r;
+	uint32_t value;
+
+	if (size & 0x3 || offset & 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;
+	}
+
+	r = amdgpu_virt_enable_access_debugfs(adev);
+	if (r < 0) {
+		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+		return r;
+	}
+
+	mutex_lock(&rd->lock);
+
+	if (rd->id.use_grbm) {
+		if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
+		    (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
+			pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
+			pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+			amdgpu_virt_disable_access_debugfs(adev);
+			mutex_unlock(&rd->lock);
+			return -EINVAL;
+		}
+		mutex_lock(&adev->grbm_idx_mutex);
+		amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
+								rd->id.grbm.sh,
+								rd->id.grbm.instance);
+	}
+
+	if (rd->id.use_srbm) {
+		mutex_lock(&adev->srbm_mutex);
+		amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
+									rd->id.srbm.queue, rd->id.srbm.vmid);
+	}
+
+	if (rd->id.pg_lock)
+		mutex_lock(&adev->pm.mutex);
+
+	while (size) {
+		if (!write_en) {
+			value = RREG32(offset >> 2);
+			r = put_user(value, (uint32_t *)buf);
+		} else {
+			r = get_user(value, (uint32_t *)buf);
+			if (!r)
+				amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
+		}
+		if (r) {
+			result = r;
+			goto end;
+		}
+		offset += 4;
+		size -= 4;
+		result += 4;
+		buf += 4;
+	}
+end:
+	if (rd->id.use_grbm) {
+		amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+		mutex_unlock(&adev->grbm_idx_mutex);
+	}
+
+	if (rd->id.use_srbm) {
+		amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
+		mutex_unlock(&adev->srbm_mutex);
+	}
+
+	if (rd->id.pg_lock)
+		mutex_unlock(&adev->pm.mutex);
+
+	mutex_unlock(&rd->lock);
+
+	pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
+	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+
+	amdgpu_virt_disable_access_debugfs(adev);
+	return result;
+}
+
+static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
+{
+	struct amdgpu_debugfs_regs2_data *rd = f->private_data;
+	int r;
+
+	switch (cmd) {
+	case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
+		mutex_lock(&rd->lock);
+		r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
+		mutex_unlock(&rd->lock);
+		return r ? -EINVAL : 0;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
+{
+	return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
+}
+
+static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
+{
+	return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
+}
+
 
 /**
  * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
@@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
 	return result;
 }
 
+static const struct file_operations amdgpu_debugfs_regs2_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
+	.read = amdgpu_debugfs_regs2_read,
+	.write = amdgpu_debugfs_regs2_write,
+	.open = amdgpu_debugfs_regs2_open,
+	.release = amdgpu_debugfs_regs2_release,
+	.llseek = default_llseek
+};
+
 static const struct file_operations amdgpu_debugfs_regs_fops = {
 	.owner = THIS_MODULE,
 	.read = amdgpu_debugfs_regs_read,
@@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
 
 static const struct file_operations *debugfs_regs[] = {
 	&amdgpu_debugfs_regs_fops,
+	&amdgpu_debugfs_regs2_fops,
 	&amdgpu_debugfs_regs_didt_fops,
 	&amdgpu_debugfs_regs_pcie_fops,
 	&amdgpu_debugfs_regs_smc_fops,
@@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
 
 static const char *debugfs_regs_names[] = {
 	"amdgpu_regs",
+	"amdgpu_regs2",
 	"amdgpu_regs_didt",
 	"amdgpu_regs_pcie",
 	"amdgpu_regs_smc",
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
index 141a8474e24f..6d4965b2d01e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
@@ -22,7 +22,6 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  *
  */
-
 /*
  * Debugfs
  */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
new file mode 100644
index 000000000000..919d9d401750
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/ioctl.h>
+
+/*
+ * MMIO debugfs IOCTL structure
+ */
+struct amdgpu_debugfs_regs2_iocdata {
+	__u32 use_srbm, use_grbm, pg_lock;
+	struct {
+		__u32 se, sh, instance;
+	} grbm;
+	struct {
+		__u32 me, pipe, queue, vmid;
+	} srbm;
+};
+
+/*
+ * MMIO debugfs state data (per file* handle)
+ */
+struct amdgpu_debugfs_regs2_data {
+	struct amdgpu_device *adev;
+	struct mutex lock;
+	struct amdgpu_debugfs_regs2_iocdata id;
+};
+
+enum AMDGPU_DEBUGFS_REGS2_CMDS {
+	AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
+};
+
+#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-25 17:26 [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5) Tom St Denis
@ 2021-08-26  9:59 ` Christian König
  2021-08-26 12:12 ` Lazar, Lijo
  1 sibling, 0 replies; 9+ messages in thread
From: Christian König @ 2021-08-26  9:59 UTC (permalink / raw)
  To: Tom St Denis, amd-gfx



Am 25.08.21 um 19:26 schrieb Tom St Denis:
> This new debugfs interface uses an IOCTL interface in order to pass
> along state information like SRBM and GRBM bank switching.  This
> new interface also allows a full 32-bit MMIO address range which
> the previous didn't.  With this new design we have room to grow
> the flexibility of the file as need be.
>
> (v2): Move read/write to .read/.write, fix style, add comment
>        for IOCTL data structure
>
> (v3): C style comments
>
> (v4): use u32 in struct and remove offset variable
>
> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>        instead of 0x3FF, use mutex for op/ioctl.
>
> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>   drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>   3 files changed, 201 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> index 277128846dd1..87766fef0b1c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> @@ -36,6 +36,7 @@
>   #include "amdgpu_rap.h"
>   #include "amdgpu_securedisplay.h"
>   #include "amdgpu_fw_attestation.h"
> +#include "amdgpu_umr.h"
>   
>   int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>   {
> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>   	return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>   }
>   
> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
> +{
> +	struct amdgpu_debugfs_regs2_data *rd;
> +
> +	rd = kzalloc(sizeof *rd, GFP_KERNEL);
> +	if (!rd)
> +		return -ENOMEM;
> +	rd->adev = file_inode(file)->i_private;
> +	file->private_data = rd;
> +	mutex_init(&rd->lock);
> +
> +	return 0;
> +}
> +
> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
> +{

You need a mutex_destroy() here now or otherwise lockdep might get angry.

Apart from that looks good to me now, feel free to add my rb.

Regards,
Christian.

> +	kfree(file->private_data);
> +	return 0;
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
> +{
> +	struct amdgpu_debugfs_regs2_data *rd = f->private_data;
> +	struct amdgpu_device *adev = rd->adev;
> +	ssize_t result = 0;
> +	int r;
> +	uint32_t value;
> +
> +	if (size & 0x3 || offset & 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;
> +	}
> +
> +	r = amdgpu_virt_enable_access_debugfs(adev);
> +	if (r < 0) {
> +		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +		return r;
> +	}
> +
> +	mutex_lock(&rd->lock);
> +
> +	if (rd->id.use_grbm) {
> +		if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
> +		    (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
> +			pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
> +			pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +			amdgpu_virt_disable_access_debugfs(adev);
> +			mutex_unlock(&rd->lock);
> +			return -EINVAL;
> +		}
> +		mutex_lock(&adev->grbm_idx_mutex);
> +		amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
> +								rd->id.grbm.sh,
> +								rd->id.grbm.instance);
> +	}
> +
> +	if (rd->id.use_srbm) {
> +		mutex_lock(&adev->srbm_mutex);
> +		amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
> +									rd->id.srbm.queue, rd->id.srbm.vmid);
> +	}
> +
> +	if (rd->id.pg_lock)
> +		mutex_lock(&adev->pm.mutex);
> +
> +	while (size) {
> +		if (!write_en) {
> +			value = RREG32(offset >> 2);
> +			r = put_user(value, (uint32_t *)buf);
> +		} else {
> +			r = get_user(value, (uint32_t *)buf);
> +			if (!r)
> +				amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
> +		}
> +		if (r) {
> +			result = r;
> +			goto end;
> +		}
> +		offset += 4;
> +		size -= 4;
> +		result += 4;
> +		buf += 4;
> +	}
> +end:
> +	if (rd->id.use_grbm) {
> +		amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
> +		mutex_unlock(&adev->grbm_idx_mutex);
> +	}
> +
> +	if (rd->id.use_srbm) {
> +		amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
> +		mutex_unlock(&adev->srbm_mutex);
> +	}
> +
> +	if (rd->id.pg_lock)
> +		mutex_unlock(&adev->pm.mutex);
> +
> +	mutex_unlock(&rd->lock);
> +
> +	pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
> +	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +
> +	amdgpu_virt_disable_access_debugfs(adev);
> +	return result;
> +}
> +
> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
> +{
> +	struct amdgpu_debugfs_regs2_data *rd = f->private_data;
> +	int r;
> +
> +	switch (cmd) {
> +	case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
> +		mutex_lock(&rd->lock);
> +		r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
> +		mutex_unlock(&rd->lock);
> +		return r ? -EINVAL : 0;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
> +{
> +	return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
> +{
> +	return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
> +}
> +
>   
>   /**
>    * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>   	return result;
>   }
>   
> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
> +	.owner = THIS_MODULE,
> +	.unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
> +	.read = amdgpu_debugfs_regs2_read,
> +	.write = amdgpu_debugfs_regs2_write,
> +	.open = amdgpu_debugfs_regs2_open,
> +	.release = amdgpu_debugfs_regs2_release,
> +	.llseek = default_llseek
> +};
> +
>   static const struct file_operations amdgpu_debugfs_regs_fops = {
>   	.owner = THIS_MODULE,
>   	.read = amdgpu_debugfs_regs_read,
> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>   
>   static const struct file_operations *debugfs_regs[] = {
>   	&amdgpu_debugfs_regs_fops,
> +	&amdgpu_debugfs_regs2_fops,
>   	&amdgpu_debugfs_regs_didt_fops,
>   	&amdgpu_debugfs_regs_pcie_fops,
>   	&amdgpu_debugfs_regs_smc_fops,
> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>   
>   static const char *debugfs_regs_names[] = {
>   	"amdgpu_regs",
> +	"amdgpu_regs2",
>   	"amdgpu_regs_didt",
>   	"amdgpu_regs_pcie",
>   	"amdgpu_regs_smc",
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> index 141a8474e24f..6d4965b2d01e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> @@ -22,7 +22,6 @@
>    * OTHER DEALINGS IN THE SOFTWARE.
>    *
>    */
> -
>   /*
>    * Debugfs
>    */
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
> new file mode 100644
> index 000000000000..919d9d401750
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright 2021 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#include <linux/ioctl.h>
> +
> +/*
> + * MMIO debugfs IOCTL structure
> + */
> +struct amdgpu_debugfs_regs2_iocdata {
> +	__u32 use_srbm, use_grbm, pg_lock;
> +	struct {
> +		__u32 se, sh, instance;
> +	} grbm;
> +	struct {
> +		__u32 me, pipe, queue, vmid;
> +	} srbm;
> +};
> +
> +/*
> + * MMIO debugfs state data (per file* handle)
> + */
> +struct amdgpu_debugfs_regs2_data {
> +	struct amdgpu_device *adev;
> +	struct mutex lock;
> +	struct amdgpu_debugfs_regs2_iocdata id;
> +};
> +
> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
> +	AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
> +};
> +
> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-25 17:26 [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5) Tom St Denis
  2021-08-26  9:59 ` Christian König
@ 2021-08-26 12:12 ` Lazar, Lijo
  2021-08-26 12:15   ` StDenis, Tom
  1 sibling, 1 reply; 9+ messages in thread
From: Lazar, Lijo @ 2021-08-26 12:12 UTC (permalink / raw)
  To: Tom St Denis, amd-gfx



On 8/25/2021 10:56 PM, Tom St Denis wrote:
> This new debugfs interface uses an IOCTL interface in order to pass
> along state information like SRBM and GRBM bank switching.  This
> new interface also allows a full 32-bit MMIO address range which
> the previous didn't.  With this new design we have room to grow
> the flexibility of the file as need be.
> 
> (v2): Move read/write to .read/.write, fix style, add comment
>        for IOCTL data structure
> 
> (v3): C style comments
> 
> (v4): use u32 in struct and remove offset variable
> 
> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>        instead of 0x3FF, use mutex for op/ioctl.
> 
> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>   drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>   3 files changed, 201 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> index 277128846dd1..87766fef0b1c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> @@ -36,6 +36,7 @@
>   #include "amdgpu_rap.h"
>   #include "amdgpu_securedisplay.h"
>   #include "amdgpu_fw_attestation.h"
> +#include "amdgpu_umr.h"
>   
>   int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>   {
> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>   	return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>   }
>   
> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
> +{
> +	struct amdgpu_debugfs_regs2_data *rd;
> +
> +	rd = kzalloc(sizeof *rd, GFP_KERNEL);
> +	if (!rd)
> +		return -ENOMEM;
> +	rd->adev = file_inode(file)->i_private;
> +	file->private_data = rd;
> +	mutex_init(&rd->lock);
> +
> +	return 0;
> +}
> +
> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
> +{
> +	kfree(file->private_data);
> +	return 0;
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
> +{
> +	struct amdgpu_debugfs_regs2_data *rd = f->private_data;
> +	struct amdgpu_device *adev = rd->adev;
> +	ssize_t result = 0;
> +	int r;
> +	uint32_t value;
> +
> +	if (size & 0x3 || offset & 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;
> +	}
> +
> +	r = amdgpu_virt_enable_access_debugfs(adev);
> +	if (r < 0) {
> +		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +		return r;
> +	}
> +
> +	mutex_lock(&rd->lock);
> +
> +	if (rd->id.use_grbm) {
> +		if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
> +		    (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
> +			pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
> +			pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +			amdgpu_virt_disable_access_debugfs(adev);
> +			mutex_unlock(&rd->lock);
> +			return -EINVAL;
> +		}
> +		mutex_lock(&adev->grbm_idx_mutex);
> +		amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
> +								rd->id.grbm.sh,
> +								rd->id.grbm.instance);
> +	}
> +
> +	if (rd->id.use_srbm) {
> +		mutex_lock(&adev->srbm_mutex);
> +		amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
> +									rd->id.srbm.queue, rd->id.srbm.vmid);
> +	}
> +
> +	if (rd->id.pg_lock)
> +		mutex_lock(&adev->pm.mutex);
> +
> +	while (size) {
> +		if (!write_en) {
> +			value = RREG32(offset >> 2);
> +			r = put_user(value, (uint32_t *)buf);
> +		} else {
> +			r = get_user(value, (uint32_t *)buf);
> +			if (!r)
> +				amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
> +		}
> +		if (r) {
> +			result = r;
> +			goto end;
> +		}
> +		offset += 4;
> +		size -= 4;
> +		result += 4;
> +		buf += 4;
> +	}
> +end:
> +	if (rd->id.use_grbm) {
> +		amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
> +		mutex_unlock(&adev->grbm_idx_mutex);
> +	}
> +
> +	if (rd->id.use_srbm) {
> +		amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
> +		mutex_unlock(&adev->srbm_mutex);
> +	}
> +
> +	if (rd->id.pg_lock)
> +		mutex_unlock(&adev->pm.mutex);
> +
> +	mutex_unlock(&rd->lock);
> +
> +	pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
> +	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +
> +	amdgpu_virt_disable_access_debugfs(adev);
> +	return result;
> +}
> +
> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
> +{
> +	struct amdgpu_debugfs_regs2_data *rd = f->private_data;
> +	int r;
> +
> +	switch (cmd) {
> +	case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
> +		mutex_lock(&rd->lock);
> +		r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
> +		mutex_unlock(&rd->lock);

As this is a two-step read/write, I don't think there is any protection 
offered by having this mutex.

Thanks,
Lijo

> +		return r ? -EINVAL : 0;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
> +{
> +	return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
> +{
> +	return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
> +}
> +
>   
>   /**
>    * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>   	return result;
>   }
>   
> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
> +	.owner = THIS_MODULE,
> +	.unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
> +	.read = amdgpu_debugfs_regs2_read,
> +	.write = amdgpu_debugfs_regs2_write,
> +	.open = amdgpu_debugfs_regs2_open,
> +	.release = amdgpu_debugfs_regs2_release,
> +	.llseek = default_llseek
> +};
> +
>   static const struct file_operations amdgpu_debugfs_regs_fops = {
>   	.owner = THIS_MODULE,
>   	.read = amdgpu_debugfs_regs_read,
> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>   
>   static const struct file_operations *debugfs_regs[] = {
>   	&amdgpu_debugfs_regs_fops,
> +	&amdgpu_debugfs_regs2_fops,
>   	&amdgpu_debugfs_regs_didt_fops,
>   	&amdgpu_debugfs_regs_pcie_fops,
>   	&amdgpu_debugfs_regs_smc_fops,
> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>   
>   static const char *debugfs_regs_names[] = {
>   	"amdgpu_regs",
> +	"amdgpu_regs2",
>   	"amdgpu_regs_didt",
>   	"amdgpu_regs_pcie",
>   	"amdgpu_regs_smc",
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> index 141a8474e24f..6d4965b2d01e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> @@ -22,7 +22,6 @@
>    * OTHER DEALINGS IN THE SOFTWARE.
>    *
>    */
> -
>   /*
>    * Debugfs
>    */
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
> new file mode 100644
> index 000000000000..919d9d401750
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright 2021 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#include <linux/ioctl.h>
> +
> +/*
> + * MMIO debugfs IOCTL structure
> + */
> +struct amdgpu_debugfs_regs2_iocdata {
> +	__u32 use_srbm, use_grbm, pg_lock;
> +	struct {
> +		__u32 se, sh, instance;
> +	} grbm;
> +	struct {
> +		__u32 me, pipe, queue, vmid;
> +	} srbm;
> +};
> +
> +/*
> + * MMIO debugfs state data (per file* handle)
> + */
> +struct amdgpu_debugfs_regs2_data {
> +	struct amdgpu_device *adev;
> +	struct mutex lock;
> +	struct amdgpu_debugfs_regs2_iocdata id;
> +};
> +
> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
> +	AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
> +};
> +
> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-26 12:12 ` Lazar, Lijo
@ 2021-08-26 12:15   ` StDenis, Tom
  2021-08-26 12:19     ` Lazar, Lijo
  0 siblings, 1 reply; 9+ messages in thread
From: StDenis, Tom @ 2021-08-26 12:15 UTC (permalink / raw)
  To: Lazar, Lijo, amd-gfx

[AMD Official Use Only]

While umr uses this as a constant two-step dance that doesn't mean another user task couldn't misbehave.  Two threads firing read/write and IOCTL at the same time could cause a lock imbalance.

As I remarked to Christian offline that's unlikely to happen since umr is the only likely user of this it's still ideal to avoid potential race conditions as a matter of correctness.

Tom

________________________________________
From: Lazar, Lijo <Lijo.Lazar@amd.com>
Sent: Thursday, August 26, 2021 08:12
To: StDenis, Tom; amd-gfx@lists.freedesktop.org
Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)



On 8/25/2021 10:56 PM, Tom St Denis wrote:
> This new debugfs interface uses an IOCTL interface in order to pass
> along state information like SRBM and GRBM bank switching.  This
> new interface also allows a full 32-bit MMIO address range which
> the previous didn't.  With this new design we have room to grow
> the flexibility of the file as need be.
>
> (v2): Move read/write to .read/.write, fix style, add comment
>        for IOCTL data structure
>
> (v3): C style comments
>
> (v4): use u32 in struct and remove offset variable
>
> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>        instead of 0x3FF, use mutex for op/ioctl.
>
> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>   drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>   3 files changed, 201 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> index 277128846dd1..87766fef0b1c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
> @@ -36,6 +36,7 @@
>   #include "amdgpu_rap.h"
>   #include "amdgpu_securedisplay.h"
>   #include "amdgpu_fw_attestation.h"
> +#include "amdgpu_umr.h"
>
>   int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>   {
> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>       return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>   }
>
> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
> +{
> +     struct amdgpu_debugfs_regs2_data *rd;
> +
> +     rd = kzalloc(sizeof *rd, GFP_KERNEL);
> +     if (!rd)
> +             return -ENOMEM;
> +     rd->adev = file_inode(file)->i_private;
> +     file->private_data = rd;
> +     mutex_init(&rd->lock);
> +
> +     return 0;
> +}
> +
> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
> +{
> +     kfree(file->private_data);
> +     return 0;
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
> +{
> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
> +     struct amdgpu_device *adev = rd->adev;
> +     ssize_t result = 0;
> +     int r;
> +     uint32_t value;
> +
> +     if (size & 0x3 || offset & 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;
> +     }
> +
> +     r = amdgpu_virt_enable_access_debugfs(adev);
> +     if (r < 0) {
> +             pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +             return r;
> +     }
> +
> +     mutex_lock(&rd->lock);
> +
> +     if (rd->id.use_grbm) {
> +             if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
> +                 (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
> +                     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
> +                     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +                     amdgpu_virt_disable_access_debugfs(adev);
> +                     mutex_unlock(&rd->lock);
> +                     return -EINVAL;
> +             }
> +             mutex_lock(&adev->grbm_idx_mutex);
> +             amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
> +                                                             rd->id.grbm.sh,
> +                                                             rd->id.grbm.instance);
> +     }
> +
> +     if (rd->id.use_srbm) {
> +             mutex_lock(&adev->srbm_mutex);
> +             amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
> +                                                                     rd->id.srbm.queue, rd->id.srbm.vmid);
> +     }
> +
> +     if (rd->id.pg_lock)
> +             mutex_lock(&adev->pm.mutex);
> +
> +     while (size) {
> +             if (!write_en) {
> +                     value = RREG32(offset >> 2);
> +                     r = put_user(value, (uint32_t *)buf);
> +             } else {
> +                     r = get_user(value, (uint32_t *)buf);
> +                     if (!r)
> +                             amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
> +             }
> +             if (r) {
> +                     result = r;
> +                     goto end;
> +             }
> +             offset += 4;
> +             size -= 4;
> +             result += 4;
> +             buf += 4;
> +     }
> +end:
> +     if (rd->id.use_grbm) {
> +             amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
> +             mutex_unlock(&adev->grbm_idx_mutex);
> +     }
> +
> +     if (rd->id.use_srbm) {
> +             amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
> +             mutex_unlock(&adev->srbm_mutex);
> +     }
> +
> +     if (rd->id.pg_lock)
> +             mutex_unlock(&adev->pm.mutex);
> +
> +     mutex_unlock(&rd->lock);
> +
> +     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
> +     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
> +
> +     amdgpu_virt_disable_access_debugfs(adev);
> +     return result;
> +}
> +
> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
> +{
> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
> +     int r;
> +
> +     switch (cmd) {
> +     case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
> +             mutex_lock(&rd->lock);
> +             r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
> +             mutex_unlock(&rd->lock);

As this is a two-step read/write, I don't think there is any protection
offered by having this mutex.

Thanks,
Lijo

> +             return r ? -EINVAL : 0;
> +     default:
> +             return -EINVAL;
> +     }
> +     return 0;
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
> +{
> +     return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
> +}
> +
> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
> +{
> +     return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
> +}
> +
>
>   /**
>    * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>       return result;
>   }
>
> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
> +     .owner = THIS_MODULE,
> +     .unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
> +     .read = amdgpu_debugfs_regs2_read,
> +     .write = amdgpu_debugfs_regs2_write,
> +     .open = amdgpu_debugfs_regs2_open,
> +     .release = amdgpu_debugfs_regs2_release,
> +     .llseek = default_llseek
> +};
> +
>   static const struct file_operations amdgpu_debugfs_regs_fops = {
>       .owner = THIS_MODULE,
>       .read = amdgpu_debugfs_regs_read,
> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>
>   static const struct file_operations *debugfs_regs[] = {
>       &amdgpu_debugfs_regs_fops,
> +     &amdgpu_debugfs_regs2_fops,
>       &amdgpu_debugfs_regs_didt_fops,
>       &amdgpu_debugfs_regs_pcie_fops,
>       &amdgpu_debugfs_regs_smc_fops,
> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>
>   static const char *debugfs_regs_names[] = {
>       "amdgpu_regs",
> +     "amdgpu_regs2",
>       "amdgpu_regs_didt",
>       "amdgpu_regs_pcie",
>       "amdgpu_regs_smc",
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> index 141a8474e24f..6d4965b2d01e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
> @@ -22,7 +22,6 @@
>    * OTHER DEALINGS IN THE SOFTWARE.
>    *
>    */
> -
>   /*
>    * Debugfs
>    */
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
> new file mode 100644
> index 000000000000..919d9d401750
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright 2021 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#include <linux/ioctl.h>
> +
> +/*
> + * MMIO debugfs IOCTL structure
> + */
> +struct amdgpu_debugfs_regs2_iocdata {
> +     __u32 use_srbm, use_grbm, pg_lock;
> +     struct {
> +             __u32 se, sh, instance;
> +     } grbm;
> +     struct {
> +             __u32 me, pipe, queue, vmid;
> +     } srbm;
> +};
> +
> +/*
> + * MMIO debugfs state data (per file* handle)
> + */
> +struct amdgpu_debugfs_regs2_data {
> +     struct amdgpu_device *adev;
> +     struct mutex lock;
> +     struct amdgpu_debugfs_regs2_iocdata id;
> +};
> +
> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
> +     AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
> +};
> +
> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-26 12:15   ` StDenis, Tom
@ 2021-08-26 12:19     ` Lazar, Lijo
  2021-08-26 12:22       ` StDenis, Tom
  0 siblings, 1 reply; 9+ messages in thread
From: Lazar, Lijo @ 2021-08-26 12:19 UTC (permalink / raw)
  To: StDenis, Tom, amd-gfx

If there are two threads using the same fd, I don't see anything that 
prevent this order

	set_state (T1) // State1
	set_state (T2) // State2
	read (T1)
	write (T2)

If there are separate fds, I guess the device level mutex takes care anyway.

Thanks,
Lijo

On 8/26/2021 5:45 PM, StDenis, Tom wrote:
> [AMD Official Use Only]
> 
> While umr uses this as a constant two-step dance that doesn't mean another user task couldn't misbehave.  Two threads firing read/write and IOCTL at the same time could cause a lock imbalance.
> 
> As I remarked to Christian offline that's unlikely to happen since umr is the only likely user of this it's still ideal to avoid potential race conditions as a matter of correctness.
> 
> Tom
> 
> ________________________________________
> From: Lazar, Lijo <Lijo.Lazar@amd.com>
> Sent: Thursday, August 26, 2021 08:12
> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
> 
> 
> 
> On 8/25/2021 10:56 PM, Tom St Denis wrote:
>> This new debugfs interface uses an IOCTL interface in order to pass
>> along state information like SRBM and GRBM bank switching.  This
>> new interface also allows a full 32-bit MMIO address range which
>> the previous didn't.  With this new design we have room to grow
>> the flexibility of the file as need be.
>>
>> (v2): Move read/write to .read/.write, fix style, add comment
>>         for IOCTL data structure
>>
>> (v3): C style comments
>>
>> (v4): use u32 in struct and remove offset variable
>>
>> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>>         instead of 0x3FF, use mutex for op/ioctl.
>>
>> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
>> ---
>>    drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>>    drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>>    drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>>    3 files changed, 201 insertions(+), 1 deletion(-)
>>    create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>> index 277128846dd1..87766fef0b1c 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>> @@ -36,6 +36,7 @@
>>    #include "amdgpu_rap.h"
>>    #include "amdgpu_securedisplay.h"
>>    #include "amdgpu_fw_attestation.h"
>> +#include "amdgpu_umr.h"
>>
>>    int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>>    {
>> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>>        return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>>    }
>>
>> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
>> +{
>> +     struct amdgpu_debugfs_regs2_data *rd;
>> +
>> +     rd = kzalloc(sizeof *rd, GFP_KERNEL);
>> +     if (!rd)
>> +             return -ENOMEM;
>> +     rd->adev = file_inode(file)->i_private;
>> +     file->private_data = rd;
>> +     mutex_init(&rd->lock);
>> +
>> +     return 0;
>> +}
>> +
>> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
>> +{
>> +     kfree(file->private_data);
>> +     return 0;
>> +}
>> +
>> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
>> +{
>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>> +     struct amdgpu_device *adev = rd->adev;
>> +     ssize_t result = 0;
>> +     int r;
>> +     uint32_t value;
>> +
>> +     if (size & 0x3 || offset & 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;
>> +     }
>> +
>> +     r = amdgpu_virt_enable_access_debugfs(adev);
>> +     if (r < 0) {
>> +             pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>> +             return r;
>> +     }
>> +
>> +     mutex_lock(&rd->lock);
>> +
>> +     if (rd->id.use_grbm) {
>> +             if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
>> +                 (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
>> +                     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>> +                     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>> +                     amdgpu_virt_disable_access_debugfs(adev);
>> +                     mutex_unlock(&rd->lock);
>> +                     return -EINVAL;
>> +             }
>> +             mutex_lock(&adev->grbm_idx_mutex);
>> +             amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
>> +                                                             rd->id.grbm.sh,
>> +                                                             rd->id.grbm.instance);
>> +     }
>> +
>> +     if (rd->id.use_srbm) {
>> +             mutex_lock(&adev->srbm_mutex);
>> +             amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
>> +                                                                     rd->id.srbm.queue, rd->id.srbm.vmid);
>> +     }
>> +
>> +     if (rd->id.pg_lock)
>> +             mutex_lock(&adev->pm.mutex);
>> +
>> +     while (size) {
>> +             if (!write_en) {
>> +                     value = RREG32(offset >> 2);
>> +                     r = put_user(value, (uint32_t *)buf);
>> +             } else {
>> +                     r = get_user(value, (uint32_t *)buf);
>> +                     if (!r)
>> +                             amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
>> +             }
>> +             if (r) {
>> +                     result = r;
>> +                     goto end;
>> +             }
>> +             offset += 4;
>> +             size -= 4;
>> +             result += 4;
>> +             buf += 4;
>> +     }
>> +end:
>> +     if (rd->id.use_grbm) {
>> +             amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
>> +             mutex_unlock(&adev->grbm_idx_mutex);
>> +     }
>> +
>> +     if (rd->id.use_srbm) {
>> +             amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
>> +             mutex_unlock(&adev->srbm_mutex);
>> +     }
>> +
>> +     if (rd->id.pg_lock)
>> +             mutex_unlock(&adev->pm.mutex);
>> +
>> +     mutex_unlock(&rd->lock);
>> +
>> +     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>> +     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>> +
>> +     amdgpu_virt_disable_access_debugfs(adev);
>> +     return result;
>> +}
>> +
>> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
>> +{
>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>> +     int r;
>> +
>> +     switch (cmd) {
>> +     case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
>> +             mutex_lock(&rd->lock);
>> +             r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
>> +             mutex_unlock(&rd->lock);
> 
> As this is a two-step read/write, I don't think there is any protection
> offered by having this mutex.
> 
> Thanks,
> Lijo
> 
>> +             return r ? -EINVAL : 0;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +     return 0;
>> +}
>> +
>> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
>> +{
>> +     return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
>> +}
>> +
>> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
>> +{
>> +     return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
>> +}
>> +
>>
>>    /**
>>     * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
>> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>>        return result;
>>    }
>>
>> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
>> +     .owner = THIS_MODULE,
>> +     .unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
>> +     .read = amdgpu_debugfs_regs2_read,
>> +     .write = amdgpu_debugfs_regs2_write,
>> +     .open = amdgpu_debugfs_regs2_open,
>> +     .release = amdgpu_debugfs_regs2_release,
>> +     .llseek = default_llseek
>> +};
>> +
>>    static const struct file_operations amdgpu_debugfs_regs_fops = {
>>        .owner = THIS_MODULE,
>>        .read = amdgpu_debugfs_regs_read,
>> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>>
>>    static const struct file_operations *debugfs_regs[] = {
>>        &amdgpu_debugfs_regs_fops,
>> +     &amdgpu_debugfs_regs2_fops,
>>        &amdgpu_debugfs_regs_didt_fops,
>>        &amdgpu_debugfs_regs_pcie_fops,
>>        &amdgpu_debugfs_regs_smc_fops,
>> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>>
>>    static const char *debugfs_regs_names[] = {
>>        "amdgpu_regs",
>> +     "amdgpu_regs2",
>>        "amdgpu_regs_didt",
>>        "amdgpu_regs_pcie",
>>        "amdgpu_regs_smc",
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>> index 141a8474e24f..6d4965b2d01e 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>> @@ -22,7 +22,6 @@
>>     * OTHER DEALINGS IN THE SOFTWARE.
>>     *
>>     */
>> -
>>    /*
>>     * Debugfs
>>     */
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>> new file mode 100644
>> index 000000000000..919d9d401750
>> --- /dev/null
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>> @@ -0,0 +1,51 @@
>> +/*
>> + * Copyright 2021 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +#include <linux/ioctl.h>
>> +
>> +/*
>> + * MMIO debugfs IOCTL structure
>> + */
>> +struct amdgpu_debugfs_regs2_iocdata {
>> +     __u32 use_srbm, use_grbm, pg_lock;
>> +     struct {
>> +             __u32 se, sh, instance;
>> +     } grbm;
>> +     struct {
>> +             __u32 me, pipe, queue, vmid;
>> +     } srbm;
>> +};
>> +
>> +/*
>> + * MMIO debugfs state data (per file* handle)
>> + */
>> +struct amdgpu_debugfs_regs2_data {
>> +     struct amdgpu_device *adev;
>> +     struct mutex lock;
>> +     struct amdgpu_debugfs_regs2_iocdata id;
>> +};
>> +
>> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
>> +     AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
>> +};
>> +
>> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-26 12:19     ` Lazar, Lijo
@ 2021-08-26 12:22       ` StDenis, Tom
  2021-08-26 12:26         ` Lazar, Lijo
  0 siblings, 1 reply; 9+ messages in thread
From: StDenis, Tom @ 2021-08-26 12:22 UTC (permalink / raw)
  To: Lazar, Lijo, amd-gfx

[AMD Official Use Only]

The issue is someone can issue an ioctl WHILE a read/write is happening.  In that case a read could take a [say] SRBM lock but then never free it.

Two threads racing operations WITH the lock in place just means the userspace gets undefined outputs which from the kernel is fine.

Tom

________________________________________
From: Lazar, Lijo <Lijo.Lazar@amd.com>
Sent: Thursday, August 26, 2021 08:19
To: StDenis, Tom; amd-gfx@lists.freedesktop.org
Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)

If there are two threads using the same fd, I don't see anything that
prevent this order

        set_state (T1) // State1
        set_state (T2) // State2
        read (T1)
        write (T2)

If there are separate fds, I guess the device level mutex takes care anyway.

Thanks,
Lijo

On 8/26/2021 5:45 PM, StDenis, Tom wrote:
> [AMD Official Use Only]
>
> While umr uses this as a constant two-step dance that doesn't mean another user task couldn't misbehave.  Two threads firing read/write and IOCTL at the same time could cause a lock imbalance.
>
> As I remarked to Christian offline that's unlikely to happen since umr is the only likely user of this it's still ideal to avoid potential race conditions as a matter of correctness.
>
> Tom
>
> ________________________________________
> From: Lazar, Lijo <Lijo.Lazar@amd.com>
> Sent: Thursday, August 26, 2021 08:12
> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
>
>
>
> On 8/25/2021 10:56 PM, Tom St Denis wrote:
>> This new debugfs interface uses an IOCTL interface in order to pass
>> along state information like SRBM and GRBM bank switching.  This
>> new interface also allows a full 32-bit MMIO address range which
>> the previous didn't.  With this new design we have room to grow
>> the flexibility of the file as need be.
>>
>> (v2): Move read/write to .read/.write, fix style, add comment
>>         for IOCTL data structure
>>
>> (v3): C style comments
>>
>> (v4): use u32 in struct and remove offset variable
>>
>> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>>         instead of 0x3FF, use mutex for op/ioctl.
>>
>> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
>> ---
>>    drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>>    drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>>    drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>>    3 files changed, 201 insertions(+), 1 deletion(-)
>>    create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>> index 277128846dd1..87766fef0b1c 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>> @@ -36,6 +36,7 @@
>>    #include "amdgpu_rap.h"
>>    #include "amdgpu_securedisplay.h"
>>    #include "amdgpu_fw_attestation.h"
>> +#include "amdgpu_umr.h"
>>
>>    int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>>    {
>> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>>        return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>>    }
>>
>> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
>> +{
>> +     struct amdgpu_debugfs_regs2_data *rd;
>> +
>> +     rd = kzalloc(sizeof *rd, GFP_KERNEL);
>> +     if (!rd)
>> +             return -ENOMEM;
>> +     rd->adev = file_inode(file)->i_private;
>> +     file->private_data = rd;
>> +     mutex_init(&rd->lock);
>> +
>> +     return 0;
>> +}
>> +
>> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
>> +{
>> +     kfree(file->private_data);
>> +     return 0;
>> +}
>> +
>> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
>> +{
>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>> +     struct amdgpu_device *adev = rd->adev;
>> +     ssize_t result = 0;
>> +     int r;
>> +     uint32_t value;
>> +
>> +     if (size & 0x3 || offset & 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;
>> +     }
>> +
>> +     r = amdgpu_virt_enable_access_debugfs(adev);
>> +     if (r < 0) {
>> +             pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>> +             return r;
>> +     }
>> +
>> +     mutex_lock(&rd->lock);
>> +
>> +     if (rd->id.use_grbm) {
>> +             if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
>> +                 (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
>> +                     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>> +                     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>> +                     amdgpu_virt_disable_access_debugfs(adev);
>> +                     mutex_unlock(&rd->lock);
>> +                     return -EINVAL;
>> +             }
>> +             mutex_lock(&adev->grbm_idx_mutex);
>> +             amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
>> +                                                             rd->id.grbm.sh,
>> +                                                             rd->id.grbm.instance);
>> +     }
>> +
>> +     if (rd->id.use_srbm) {
>> +             mutex_lock(&adev->srbm_mutex);
>> +             amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
>> +                                                                     rd->id.srbm.queue, rd->id.srbm.vmid);
>> +     }
>> +
>> +     if (rd->id.pg_lock)
>> +             mutex_lock(&adev->pm.mutex);
>> +
>> +     while (size) {
>> +             if (!write_en) {
>> +                     value = RREG32(offset >> 2);
>> +                     r = put_user(value, (uint32_t *)buf);
>> +             } else {
>> +                     r = get_user(value, (uint32_t *)buf);
>> +                     if (!r)
>> +                             amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
>> +             }
>> +             if (r) {
>> +                     result = r;
>> +                     goto end;
>> +             }
>> +             offset += 4;
>> +             size -= 4;
>> +             result += 4;
>> +             buf += 4;
>> +     }
>> +end:
>> +     if (rd->id.use_grbm) {
>> +             amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
>> +             mutex_unlock(&adev->grbm_idx_mutex);
>> +     }
>> +
>> +     if (rd->id.use_srbm) {
>> +             amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
>> +             mutex_unlock(&adev->srbm_mutex);
>> +     }
>> +
>> +     if (rd->id.pg_lock)
>> +             mutex_unlock(&adev->pm.mutex);
>> +
>> +     mutex_unlock(&rd->lock);
>> +
>> +     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>> +     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>> +
>> +     amdgpu_virt_disable_access_debugfs(adev);
>> +     return result;
>> +}
>> +
>> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
>> +{
>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>> +     int r;
>> +
>> +     switch (cmd) {
>> +     case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
>> +             mutex_lock(&rd->lock);
>> +             r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
>> +             mutex_unlock(&rd->lock);
>
> As this is a two-step read/write, I don't think there is any protection
> offered by having this mutex.
>
> Thanks,
> Lijo
>
>> +             return r ? -EINVAL : 0;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +     return 0;
>> +}
>> +
>> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
>> +{
>> +     return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
>> +}
>> +
>> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
>> +{
>> +     return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
>> +}
>> +
>>
>>    /**
>>     * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
>> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>>        return result;
>>    }
>>
>> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
>> +     .owner = THIS_MODULE,
>> +     .unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
>> +     .read = amdgpu_debugfs_regs2_read,
>> +     .write = amdgpu_debugfs_regs2_write,
>> +     .open = amdgpu_debugfs_regs2_open,
>> +     .release = amdgpu_debugfs_regs2_release,
>> +     .llseek = default_llseek
>> +};
>> +
>>    static const struct file_operations amdgpu_debugfs_regs_fops = {
>>        .owner = THIS_MODULE,
>>        .read = amdgpu_debugfs_regs_read,
>> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>>
>>    static const struct file_operations *debugfs_regs[] = {
>>        &amdgpu_debugfs_regs_fops,
>> +     &amdgpu_debugfs_regs2_fops,
>>        &amdgpu_debugfs_regs_didt_fops,
>>        &amdgpu_debugfs_regs_pcie_fops,
>>        &amdgpu_debugfs_regs_smc_fops,
>> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>>
>>    static const char *debugfs_regs_names[] = {
>>        "amdgpu_regs",
>> +     "amdgpu_regs2",
>>        "amdgpu_regs_didt",
>>        "amdgpu_regs_pcie",
>>        "amdgpu_regs_smc",
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>> index 141a8474e24f..6d4965b2d01e 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>> @@ -22,7 +22,6 @@
>>     * OTHER DEALINGS IN THE SOFTWARE.
>>     *
>>     */
>> -
>>    /*
>>     * Debugfs
>>     */
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>> new file mode 100644
>> index 000000000000..919d9d401750
>> --- /dev/null
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>> @@ -0,0 +1,51 @@
>> +/*
>> + * Copyright 2021 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +#include <linux/ioctl.h>
>> +
>> +/*
>> + * MMIO debugfs IOCTL structure
>> + */
>> +struct amdgpu_debugfs_regs2_iocdata {
>> +     __u32 use_srbm, use_grbm, pg_lock;
>> +     struct {
>> +             __u32 se, sh, instance;
>> +     } grbm;
>> +     struct {
>> +             __u32 me, pipe, queue, vmid;
>> +     } srbm;
>> +};
>> +
>> +/*
>> + * MMIO debugfs state data (per file* handle)
>> + */
>> +struct amdgpu_debugfs_regs2_data {
>> +     struct amdgpu_device *adev;
>> +     struct mutex lock;
>> +     struct amdgpu_debugfs_regs2_iocdata id;
>> +};
>> +
>> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
>> +     AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
>> +};
>> +
>> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-26 12:22       ` StDenis, Tom
@ 2021-08-26 12:26         ` Lazar, Lijo
  2021-08-26 12:28           ` StDenis, Tom
  0 siblings, 1 reply; 9+ messages in thread
From: Lazar, Lijo @ 2021-08-26 12:26 UTC (permalink / raw)
  To: StDenis, Tom, amd-gfx

Does that really need a lock? Can't local variables solve it?

Thanks,
Lijo

On 8/26/2021 5:52 PM, StDenis, Tom wrote:
> [AMD Official Use Only]
> 
> The issue is someone can issue an ioctl WHILE a read/write is happening.  In that case a read could take a [say] SRBM lock but then never free it.
> 
> Two threads racing operations WITH the lock in place just means the userspace gets undefined outputs which from the kernel is fine.
> 
> Tom
> 
> ________________________________________
> From: Lazar, Lijo <Lijo.Lazar@amd.com>
> Sent: Thursday, August 26, 2021 08:19
> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
> 
> If there are two threads using the same fd, I don't see anything that
> prevent this order
> 
>          set_state (T1) // State1
>          set_state (T2) // State2
>          read (T1)
>          write (T2)
> 
> If there are separate fds, I guess the device level mutex takes care anyway.
> 
> Thanks,
> Lijo
> 
> On 8/26/2021 5:45 PM, StDenis, Tom wrote:
>> [AMD Official Use Only]
>>
>> While umr uses this as a constant two-step dance that doesn't mean another user task couldn't misbehave.  Two threads firing read/write and IOCTL at the same time could cause a lock imbalance.
>>
>> As I remarked to Christian offline that's unlikely to happen since umr is the only likely user of this it's still ideal to avoid potential race conditions as a matter of correctness.
>>
>> Tom
>>
>> ________________________________________
>> From: Lazar, Lijo <Lijo.Lazar@amd.com>
>> Sent: Thursday, August 26, 2021 08:12
>> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
>> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
>>
>>
>>
>> On 8/25/2021 10:56 PM, Tom St Denis wrote:
>>> This new debugfs interface uses an IOCTL interface in order to pass
>>> along state information like SRBM and GRBM bank switching.  This
>>> new interface also allows a full 32-bit MMIO address range which
>>> the previous didn't.  With this new design we have room to grow
>>> the flexibility of the file as need be.
>>>
>>> (v2): Move read/write to .read/.write, fix style, add comment
>>>          for IOCTL data structure
>>>
>>> (v3): C style comments
>>>
>>> (v4): use u32 in struct and remove offset variable
>>>
>>> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>>>          instead of 0x3FF, use mutex for op/ioctl.
>>>
>>> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
>>> ---
>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>>>     3 files changed, 201 insertions(+), 1 deletion(-)
>>>     create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>> index 277128846dd1..87766fef0b1c 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>> @@ -36,6 +36,7 @@
>>>     #include "amdgpu_rap.h"
>>>     #include "amdgpu_securedisplay.h"
>>>     #include "amdgpu_fw_attestation.h"
>>> +#include "amdgpu_umr.h"
>>>
>>>     int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>>>     {
>>> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>>>         return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>>>     }
>>>
>>> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
>>> +{
>>> +     struct amdgpu_debugfs_regs2_data *rd;
>>> +
>>> +     rd = kzalloc(sizeof *rd, GFP_KERNEL);
>>> +     if (!rd)
>>> +             return -ENOMEM;
>>> +     rd->adev = file_inode(file)->i_private;
>>> +     file->private_data = rd;
>>> +     mutex_init(&rd->lock);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
>>> +{
>>> +     kfree(file->private_data);
>>> +     return 0;
>>> +}
>>> +
>>> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
>>> +{
>>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>>> +     struct amdgpu_device *adev = rd->adev;
>>> +     ssize_t result = 0;
>>> +     int r;
>>> +     uint32_t value;
>>> +
>>> +     if (size & 0x3 || offset & 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;
>>> +     }
>>> +
>>> +     r = amdgpu_virt_enable_access_debugfs(adev);
>>> +     if (r < 0) {
>>> +             pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>> +             return r;
>>> +     }
>>> +
>>> +     mutex_lock(&rd->lock);
>>> +
>>> +     if (rd->id.use_grbm) {
>>> +             if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
>>> +                 (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
>>> +                     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>>> +                     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>> +                     amdgpu_virt_disable_access_debugfs(adev);
>>> +                     mutex_unlock(&rd->lock);
>>> +                     return -EINVAL;
>>> +             }
>>> +             mutex_lock(&adev->grbm_idx_mutex);
>>> +             amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
>>> +                                                             rd->id.grbm.sh,
>>> +                                                             rd->id.grbm.instance);
>>> +     }
>>> +
>>> +     if (rd->id.use_srbm) {
>>> +             mutex_lock(&adev->srbm_mutex);
>>> +             amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
>>> +                                                                     rd->id.srbm.queue, rd->id.srbm.vmid);
>>> +     }
>>> +
>>> +     if (rd->id.pg_lock)
>>> +             mutex_lock(&adev->pm.mutex);
>>> +
>>> +     while (size) {
>>> +             if (!write_en) {
>>> +                     value = RREG32(offset >> 2);
>>> +                     r = put_user(value, (uint32_t *)buf);
>>> +             } else {
>>> +                     r = get_user(value, (uint32_t *)buf);
>>> +                     if (!r)
>>> +                             amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
>>> +             }
>>> +             if (r) {
>>> +                     result = r;
>>> +                     goto end;
>>> +             }
>>> +             offset += 4;
>>> +             size -= 4;
>>> +             result += 4;
>>> +             buf += 4;
>>> +     }
>>> +end:
>>> +     if (rd->id.use_grbm) {
>>> +             amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
>>> +             mutex_unlock(&adev->grbm_idx_mutex);
>>> +     }
>>> +
>>> +     if (rd->id.use_srbm) {
>>> +             amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
>>> +             mutex_unlock(&adev->srbm_mutex);
>>> +     }
>>> +
>>> +     if (rd->id.pg_lock)
>>> +             mutex_unlock(&adev->pm.mutex);
>>> +
>>> +     mutex_unlock(&rd->lock);
>>> +
>>> +     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>>> +     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>> +
>>> +     amdgpu_virt_disable_access_debugfs(adev);
>>> +     return result;
>>> +}
>>> +
>>> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
>>> +{
>>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>>> +     int r;
>>> +
>>> +     switch (cmd) {
>>> +     case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
>>> +             mutex_lock(&rd->lock);
>>> +             r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
>>> +             mutex_unlock(&rd->lock);
>>
>> As this is a two-step read/write, I don't think there is any protection
>> offered by having this mutex.
>>
>> Thanks,
>> Lijo
>>
>>> +             return r ? -EINVAL : 0;
>>> +     default:
>>> +             return -EINVAL;
>>> +     }
>>> +     return 0;
>>> +}
>>> +
>>> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
>>> +{
>>> +     return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
>>> +}
>>> +
>>> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
>>> +{
>>> +     return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
>>> +}
>>> +
>>>
>>>     /**
>>>      * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
>>> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>>>         return result;
>>>     }
>>>
>>> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
>>> +     .owner = THIS_MODULE,
>>> +     .unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
>>> +     .read = amdgpu_debugfs_regs2_read,
>>> +     .write = amdgpu_debugfs_regs2_write,
>>> +     .open = amdgpu_debugfs_regs2_open,
>>> +     .release = amdgpu_debugfs_regs2_release,
>>> +     .llseek = default_llseek
>>> +};
>>> +
>>>     static const struct file_operations amdgpu_debugfs_regs_fops = {
>>>         .owner = THIS_MODULE,
>>>         .read = amdgpu_debugfs_regs_read,
>>> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>>>
>>>     static const struct file_operations *debugfs_regs[] = {
>>>         &amdgpu_debugfs_regs_fops,
>>> +     &amdgpu_debugfs_regs2_fops,
>>>         &amdgpu_debugfs_regs_didt_fops,
>>>         &amdgpu_debugfs_regs_pcie_fops,
>>>         &amdgpu_debugfs_regs_smc_fops,
>>> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>>>
>>>     static const char *debugfs_regs_names[] = {
>>>         "amdgpu_regs",
>>> +     "amdgpu_regs2",
>>>         "amdgpu_regs_didt",
>>>         "amdgpu_regs_pcie",
>>>         "amdgpu_regs_smc",
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>> index 141a8474e24f..6d4965b2d01e 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>> @@ -22,7 +22,6 @@
>>>      * OTHER DEALINGS IN THE SOFTWARE.
>>>      *
>>>      */
>>> -
>>>     /*
>>>      * Debugfs
>>>      */
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>> new file mode 100644
>>> index 000000000000..919d9d401750
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>> @@ -0,0 +1,51 @@
>>> +/*
>>> + * Copyright 2021 Advanced Micro Devices, Inc.
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining a
>>> + * copy of this software and associated documentation files (the "Software"),
>>> + * to deal in the Software without restriction, including without limitation
>>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>> + * Software is furnished to do so, subject to the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice shall be included in
>>> + * all copies or substantial portions of the Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>>> + * OTHER DEALINGS IN THE SOFTWARE.
>>> + *
>>> + */
>>> +#include <linux/ioctl.h>
>>> +
>>> +/*
>>> + * MMIO debugfs IOCTL structure
>>> + */
>>> +struct amdgpu_debugfs_regs2_iocdata {
>>> +     __u32 use_srbm, use_grbm, pg_lock;
>>> +     struct {
>>> +             __u32 se, sh, instance;
>>> +     } grbm;
>>> +     struct {
>>> +             __u32 me, pipe, queue, vmid;
>>> +     } srbm;
>>> +};
>>> +
>>> +/*
>>> + * MMIO debugfs state data (per file* handle)
>>> + */
>>> +struct amdgpu_debugfs_regs2_data {
>>> +     struct amdgpu_device *adev;
>>> +     struct mutex lock;
>>> +     struct amdgpu_debugfs_regs2_iocdata id;
>>> +};
>>> +
>>> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
>>> +     AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
>>> +};
>>> +
>>> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
>>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-26 12:26         ` Lazar, Lijo
@ 2021-08-26 12:28           ` StDenis, Tom
  2021-08-26 12:56             ` Christian König
  0 siblings, 1 reply; 9+ messages in thread
From: StDenis, Tom @ 2021-08-26 12:28 UTC (permalink / raw)
  To: Lazar, Lijo, amd-gfx

[AMD Official Use Only]

The state is set with one syscall and used with a different syscall.  They're not atomic.

(I also don't see the need to bikeshed this anymore than we already have).

Tom

________________________________________
From: Lazar, Lijo <Lijo.Lazar@amd.com>
Sent: Thursday, August 26, 2021 08:26
To: StDenis, Tom; amd-gfx@lists.freedesktop.org
Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)

Does that really need a lock? Can't local variables solve it?

Thanks,
Lijo

On 8/26/2021 5:52 PM, StDenis, Tom wrote:
> [AMD Official Use Only]
>
> The issue is someone can issue an ioctl WHILE a read/write is happening.  In that case a read could take a [say] SRBM lock but then never free it.
>
> Two threads racing operations WITH the lock in place just means the userspace gets undefined outputs which from the kernel is fine.
>
> Tom
>
> ________________________________________
> From: Lazar, Lijo <Lijo.Lazar@amd.com>
> Sent: Thursday, August 26, 2021 08:19
> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
>
> If there are two threads using the same fd, I don't see anything that
> prevent this order
>
>          set_state (T1) // State1
>          set_state (T2) // State2
>          read (T1)
>          write (T2)
>
> If there are separate fds, I guess the device level mutex takes care anyway.
>
> Thanks,
> Lijo
>
> On 8/26/2021 5:45 PM, StDenis, Tom wrote:
>> [AMD Official Use Only]
>>
>> While umr uses this as a constant two-step dance that doesn't mean another user task couldn't misbehave.  Two threads firing read/write and IOCTL at the same time could cause a lock imbalance.
>>
>> As I remarked to Christian offline that's unlikely to happen since umr is the only likely user of this it's still ideal to avoid potential race conditions as a matter of correctness.
>>
>> Tom
>>
>> ________________________________________
>> From: Lazar, Lijo <Lijo.Lazar@amd.com>
>> Sent: Thursday, August 26, 2021 08:12
>> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
>> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
>>
>>
>>
>> On 8/25/2021 10:56 PM, Tom St Denis wrote:
>>> This new debugfs interface uses an IOCTL interface in order to pass
>>> along state information like SRBM and GRBM bank switching.  This
>>> new interface also allows a full 32-bit MMIO address range which
>>> the previous didn't.  With this new design we have room to grow
>>> the flexibility of the file as need be.
>>>
>>> (v2): Move read/write to .read/.write, fix style, add comment
>>>          for IOCTL data structure
>>>
>>> (v3): C style comments
>>>
>>> (v4): use u32 in struct and remove offset variable
>>>
>>> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>>>          instead of 0x3FF, use mutex for op/ioctl.
>>>
>>> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
>>> ---
>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>>>     3 files changed, 201 insertions(+), 1 deletion(-)
>>>     create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>> index 277128846dd1..87766fef0b1c 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>> @@ -36,6 +36,7 @@
>>>     #include "amdgpu_rap.h"
>>>     #include "amdgpu_securedisplay.h"
>>>     #include "amdgpu_fw_attestation.h"
>>> +#include "amdgpu_umr.h"
>>>
>>>     int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>>>     {
>>> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>>>         return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>>>     }
>>>
>>> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
>>> +{
>>> +     struct amdgpu_debugfs_regs2_data *rd;
>>> +
>>> +     rd = kzalloc(sizeof *rd, GFP_KERNEL);
>>> +     if (!rd)
>>> +             return -ENOMEM;
>>> +     rd->adev = file_inode(file)->i_private;
>>> +     file->private_data = rd;
>>> +     mutex_init(&rd->lock);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
>>> +{
>>> +     kfree(file->private_data);
>>> +     return 0;
>>> +}
>>> +
>>> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
>>> +{
>>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>>> +     struct amdgpu_device *adev = rd->adev;
>>> +     ssize_t result = 0;
>>> +     int r;
>>> +     uint32_t value;
>>> +
>>> +     if (size & 0x3 || offset & 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;
>>> +     }
>>> +
>>> +     r = amdgpu_virt_enable_access_debugfs(adev);
>>> +     if (r < 0) {
>>> +             pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>> +             return r;
>>> +     }
>>> +
>>> +     mutex_lock(&rd->lock);
>>> +
>>> +     if (rd->id.use_grbm) {
>>> +             if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
>>> +                 (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
>>> +                     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>>> +                     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>> +                     amdgpu_virt_disable_access_debugfs(adev);
>>> +                     mutex_unlock(&rd->lock);
>>> +                     return -EINVAL;
>>> +             }
>>> +             mutex_lock(&adev->grbm_idx_mutex);
>>> +             amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
>>> +                                                             rd->id.grbm.sh,
>>> +                                                             rd->id.grbm.instance);
>>> +     }
>>> +
>>> +     if (rd->id.use_srbm) {
>>> +             mutex_lock(&adev->srbm_mutex);
>>> +             amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
>>> +                                                                     rd->id.srbm.queue, rd->id.srbm.vmid);
>>> +     }
>>> +
>>> +     if (rd->id.pg_lock)
>>> +             mutex_lock(&adev->pm.mutex);
>>> +
>>> +     while (size) {
>>> +             if (!write_en) {
>>> +                     value = RREG32(offset >> 2);
>>> +                     r = put_user(value, (uint32_t *)buf);
>>> +             } else {
>>> +                     r = get_user(value, (uint32_t *)buf);
>>> +                     if (!r)
>>> +                             amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
>>> +             }
>>> +             if (r) {
>>> +                     result = r;
>>> +                     goto end;
>>> +             }
>>> +             offset += 4;
>>> +             size -= 4;
>>> +             result += 4;
>>> +             buf += 4;
>>> +     }
>>> +end:
>>> +     if (rd->id.use_grbm) {
>>> +             amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
>>> +             mutex_unlock(&adev->grbm_idx_mutex);
>>> +     }
>>> +
>>> +     if (rd->id.use_srbm) {
>>> +             amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
>>> +             mutex_unlock(&adev->srbm_mutex);
>>> +     }
>>> +
>>> +     if (rd->id.pg_lock)
>>> +             mutex_unlock(&adev->pm.mutex);
>>> +
>>> +     mutex_unlock(&rd->lock);
>>> +
>>> +     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>>> +     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>> +
>>> +     amdgpu_virt_disable_access_debugfs(adev);
>>> +     return result;
>>> +}
>>> +
>>> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
>>> +{
>>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>>> +     int r;
>>> +
>>> +     switch (cmd) {
>>> +     case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
>>> +             mutex_lock(&rd->lock);
>>> +             r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
>>> +             mutex_unlock(&rd->lock);
>>
>> As this is a two-step read/write, I don't think there is any protection
>> offered by having this mutex.
>>
>> Thanks,
>> Lijo
>>
>>> +             return r ? -EINVAL : 0;
>>> +     default:
>>> +             return -EINVAL;
>>> +     }
>>> +     return 0;
>>> +}
>>> +
>>> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
>>> +{
>>> +     return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
>>> +}
>>> +
>>> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
>>> +{
>>> +     return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
>>> +}
>>> +
>>>
>>>     /**
>>>      * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
>>> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>>>         return result;
>>>     }
>>>
>>> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
>>> +     .owner = THIS_MODULE,
>>> +     .unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
>>> +     .read = amdgpu_debugfs_regs2_read,
>>> +     .write = amdgpu_debugfs_regs2_write,
>>> +     .open = amdgpu_debugfs_regs2_open,
>>> +     .release = amdgpu_debugfs_regs2_release,
>>> +     .llseek = default_llseek
>>> +};
>>> +
>>>     static const struct file_operations amdgpu_debugfs_regs_fops = {
>>>         .owner = THIS_MODULE,
>>>         .read = amdgpu_debugfs_regs_read,
>>> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>>>
>>>     static const struct file_operations *debugfs_regs[] = {
>>>         &amdgpu_debugfs_regs_fops,
>>> +     &amdgpu_debugfs_regs2_fops,
>>>         &amdgpu_debugfs_regs_didt_fops,
>>>         &amdgpu_debugfs_regs_pcie_fops,
>>>         &amdgpu_debugfs_regs_smc_fops,
>>> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>>>
>>>     static const char *debugfs_regs_names[] = {
>>>         "amdgpu_regs",
>>> +     "amdgpu_regs2",
>>>         "amdgpu_regs_didt",
>>>         "amdgpu_regs_pcie",
>>>         "amdgpu_regs_smc",
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>> index 141a8474e24f..6d4965b2d01e 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>> @@ -22,7 +22,6 @@
>>>      * OTHER DEALINGS IN THE SOFTWARE.
>>>      *
>>>      */
>>> -
>>>     /*
>>>      * Debugfs
>>>      */
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>> new file mode 100644
>>> index 000000000000..919d9d401750
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>> @@ -0,0 +1,51 @@
>>> +/*
>>> + * Copyright 2021 Advanced Micro Devices, Inc.
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining a
>>> + * copy of this software and associated documentation files (the "Software"),
>>> + * to deal in the Software without restriction, including without limitation
>>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>> + * Software is furnished to do so, subject to the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice shall be included in
>>> + * all copies or substantial portions of the Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>>> + * OTHER DEALINGS IN THE SOFTWARE.
>>> + *
>>> + */
>>> +#include <linux/ioctl.h>
>>> +
>>> +/*
>>> + * MMIO debugfs IOCTL structure
>>> + */
>>> +struct amdgpu_debugfs_regs2_iocdata {
>>> +     __u32 use_srbm, use_grbm, pg_lock;
>>> +     struct {
>>> +             __u32 se, sh, instance;
>>> +     } grbm;
>>> +     struct {
>>> +             __u32 me, pipe, queue, vmid;
>>> +     } srbm;
>>> +};
>>> +
>>> +/*
>>> + * MMIO debugfs state data (per file* handle)
>>> + */
>>> +struct amdgpu_debugfs_regs2_data {
>>> +     struct amdgpu_device *adev;
>>> +     struct mutex lock;
>>> +     struct amdgpu_debugfs_regs2_iocdata id;
>>> +};
>>> +
>>> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
>>> +     AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
>>> +};
>>> +
>>> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
>>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
  2021-08-26 12:28           ` StDenis, Tom
@ 2021-08-26 12:56             ` Christian König
  0 siblings, 0 replies; 9+ messages in thread
From: Christian König @ 2021-08-26 12:56 UTC (permalink / raw)
  To: StDenis, Tom, Lazar, Lijo, amd-gfx

Well for the record you can do something like using READ_ONCE() and work 
with a local copy.

But Tom is right we shouldn't spend much more time on this.

Christian.

Am 26.08.21 um 14:28 schrieb StDenis, Tom:
> [AMD Official Use Only]
>
> The state is set with one syscall and used with a different syscall.  They're not atomic.
>
> (I also don't see the need to bikeshed this anymore than we already have).
>
> Tom
>
> ________________________________________
> From: Lazar, Lijo <Lijo.Lazar@amd.com>
> Sent: Thursday, August 26, 2021 08:26
> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
>
> Does that really need a lock? Can't local variables solve it?
>
> Thanks,
> Lijo
>
> On 8/26/2021 5:52 PM, StDenis, Tom wrote:
>> [AMD Official Use Only]
>>
>> The issue is someone can issue an ioctl WHILE a read/write is happening.  In that case a read could take a [say] SRBM lock but then never free it.
>>
>> Two threads racing operations WITH the lock in place just means the userspace gets undefined outputs which from the kernel is fine.
>>
>> Tom
>>
>> ________________________________________
>> From: Lazar, Lijo <Lijo.Lazar@amd.com>
>> Sent: Thursday, August 26, 2021 08:19
>> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
>> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
>>
>> If there are two threads using the same fd, I don't see anything that
>> prevent this order
>>
>>           set_state (T1) // State1
>>           set_state (T2) // State2
>>           read (T1)
>>           write (T2)
>>
>> If there are separate fds, I guess the device level mutex takes care anyway.
>>
>> Thanks,
>> Lijo
>>
>> On 8/26/2021 5:45 PM, StDenis, Tom wrote:
>>> [AMD Official Use Only]
>>>
>>> While umr uses this as a constant two-step dance that doesn't mean another user task couldn't misbehave.  Two threads firing read/write and IOCTL at the same time could cause a lock imbalance.
>>>
>>> As I remarked to Christian offline that's unlikely to happen since umr is the only likely user of this it's still ideal to avoid potential race conditions as a matter of correctness.
>>>
>>> Tom
>>>
>>> ________________________________________
>>> From: Lazar, Lijo <Lijo.Lazar@amd.com>
>>> Sent: Thursday, August 26, 2021 08:12
>>> To: StDenis, Tom; amd-gfx@lists.freedesktop.org
>>> Subject: Re: [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5)
>>>
>>>
>>>
>>> On 8/25/2021 10:56 PM, Tom St Denis wrote:
>>>> This new debugfs interface uses an IOCTL interface in order to pass
>>>> along state information like SRBM and GRBM bank switching.  This
>>>> new interface also allows a full 32-bit MMIO address range which
>>>> the previous didn't.  With this new design we have room to grow
>>>> the flexibility of the file as need be.
>>>>
>>>> (v2): Move read/write to .read/.write, fix style, add comment
>>>>           for IOCTL data structure
>>>>
>>>> (v3): C style comments
>>>>
>>>> (v4): use u32 in struct and remove offset variable
>>>>
>>>> (v5): Drop flag clearing in op function, use 0xFFFFFFFF for broadcast
>>>>           instead of 0x3FF, use mutex for op/ioctl.
>>>>
>>>> Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
>>>> ---
>>>>      drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 150 ++++++++++++++++++++
>>>>      drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h |   1 -
>>>>      drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h     |  51 +++++++
>>>>      3 files changed, 201 insertions(+), 1 deletion(-)
>>>>      create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>>>
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>>> index 277128846dd1..87766fef0b1c 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
>>>> @@ -36,6 +36,7 @@
>>>>      #include "amdgpu_rap.h"
>>>>      #include "amdgpu_securedisplay.h"
>>>>      #include "amdgpu_fw_attestation.h"
>>>> +#include "amdgpu_umr.h"
>>>>
>>>>      int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
>>>>      {
>>>> @@ -279,6 +280,143 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
>>>>          return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
>>>>      }
>>>>
>>>> +static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file)
>>>> +{
>>>> +     struct amdgpu_debugfs_regs2_data *rd;
>>>> +
>>>> +     rd = kzalloc(sizeof *rd, GFP_KERNEL);
>>>> +     if (!rd)
>>>> +             return -ENOMEM;
>>>> +     rd->adev = file_inode(file)->i_private;
>>>> +     file->private_data = rd;
>>>> +     mutex_init(&rd->lock);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file)
>>>> +{
>>>> +     kfree(file->private_data);
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en)
>>>> +{
>>>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>>>> +     struct amdgpu_device *adev = rd->adev;
>>>> +     ssize_t result = 0;
>>>> +     int r;
>>>> +     uint32_t value;
>>>> +
>>>> +     if (size & 0x3 || offset & 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;
>>>> +     }
>>>> +
>>>> +     r = amdgpu_virt_enable_access_debugfs(adev);
>>>> +     if (r < 0) {
>>>> +             pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>>> +             return r;
>>>> +     }
>>>> +
>>>> +     mutex_lock(&rd->lock);
>>>> +
>>>> +     if (rd->id.use_grbm) {
>>>> +             if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) ||
>>>> +                 (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) {
>>>> +                     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>>>> +                     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>>> +                     amdgpu_virt_disable_access_debugfs(adev);
>>>> +                     mutex_unlock(&rd->lock);
>>>> +                     return -EINVAL;
>>>> +             }
>>>> +             mutex_lock(&adev->grbm_idx_mutex);
>>>> +             amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se,
>>>> +                                                             rd->id.grbm.sh,
>>>> +                                                             rd->id.grbm.instance);
>>>> +     }
>>>> +
>>>> +     if (rd->id.use_srbm) {
>>>> +             mutex_lock(&adev->srbm_mutex);
>>>> +             amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe,
>>>> +                                                                     rd->id.srbm.queue, rd->id.srbm.vmid);
>>>> +     }
>>>> +
>>>> +     if (rd->id.pg_lock)
>>>> +             mutex_lock(&adev->pm.mutex);
>>>> +
>>>> +     while (size) {
>>>> +             if (!write_en) {
>>>> +                     value = RREG32(offset >> 2);
>>>> +                     r = put_user(value, (uint32_t *)buf);
>>>> +             } else {
>>>> +                     r = get_user(value, (uint32_t *)buf);
>>>> +                     if (!r)
>>>> +                             amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value);
>>>> +             }
>>>> +             if (r) {
>>>> +                     result = r;
>>>> +                     goto end;
>>>> +             }
>>>> +             offset += 4;
>>>> +             size -= 4;
>>>> +             result += 4;
>>>> +             buf += 4;
>>>> +     }
>>>> +end:
>>>> +     if (rd->id.use_grbm) {
>>>> +             amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
>>>> +             mutex_unlock(&adev->grbm_idx_mutex);
>>>> +     }
>>>> +
>>>> +     if (rd->id.use_srbm) {
>>>> +             amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
>>>> +             mutex_unlock(&adev->srbm_mutex);
>>>> +     }
>>>> +
>>>> +     if (rd->id.pg_lock)
>>>> +             mutex_unlock(&adev->pm.mutex);
>>>> +
>>>> +     mutex_unlock(&rd->lock);
>>>> +
>>>> +     pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
>>>> +     pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
>>>> +
>>>> +     amdgpu_virt_disable_access_debugfs(adev);
>>>> +     return result;
>>>> +}
>>>> +
>>>> +static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data)
>>>> +{
>>>> +     struct amdgpu_debugfs_regs2_data *rd = f->private_data;
>>>> +     int r;
>>>> +
>>>> +     switch (cmd) {
>>>> +     case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE:
>>>> +             mutex_lock(&rd->lock);
>>>> +             r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id);
>>>> +             mutex_unlock(&rd->lock);
>>> As this is a two-step read/write, I don't think there is any protection
>>> offered by having this mutex.
>>>
>>> Thanks,
>>> Lijo
>>>
>>>> +             return r ? -EINVAL : 0;
>>>> +     default:
>>>> +             return -EINVAL;
>>>> +     }
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos)
>>>> +{
>>>> +     return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0);
>>>> +}
>>>> +
>>>> +static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos)
>>>> +{
>>>> +     return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1);
>>>> +}
>>>> +
>>>>
>>>>      /**
>>>>       * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
>>>> @@ -1091,6 +1229,16 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf,
>>>>          return result;
>>>>      }
>>>>
>>>> +static const struct file_operations amdgpu_debugfs_regs2_fops = {
>>>> +     .owner = THIS_MODULE,
>>>> +     .unlocked_ioctl = amdgpu_debugfs_regs2_ioctl,
>>>> +     .read = amdgpu_debugfs_regs2_read,
>>>> +     .write = amdgpu_debugfs_regs2_write,
>>>> +     .open = amdgpu_debugfs_regs2_open,
>>>> +     .release = amdgpu_debugfs_regs2_release,
>>>> +     .llseek = default_llseek
>>>> +};
>>>> +
>>>>      static const struct file_operations amdgpu_debugfs_regs_fops = {
>>>>          .owner = THIS_MODULE,
>>>>          .read = amdgpu_debugfs_regs_read,
>>>> @@ -1148,6 +1296,7 @@ static const struct file_operations amdgpu_debugfs_gfxoff_fops = {
>>>>
>>>>      static const struct file_operations *debugfs_regs[] = {
>>>>          &amdgpu_debugfs_regs_fops,
>>>> +     &amdgpu_debugfs_regs2_fops,
>>>>          &amdgpu_debugfs_regs_didt_fops,
>>>>          &amdgpu_debugfs_regs_pcie_fops,
>>>>          &amdgpu_debugfs_regs_smc_fops,
>>>> @@ -1160,6 +1309,7 @@ static const struct file_operations *debugfs_regs[] = {
>>>>
>>>>      static const char *debugfs_regs_names[] = {
>>>>          "amdgpu_regs",
>>>> +     "amdgpu_regs2",
>>>>          "amdgpu_regs_didt",
>>>>          "amdgpu_regs_pcie",
>>>>          "amdgpu_regs_smc",
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>>> index 141a8474e24f..6d4965b2d01e 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
>>>> @@ -22,7 +22,6 @@
>>>>       * OTHER DEALINGS IN THE SOFTWARE.
>>>>       *
>>>>       */
>>>> -
>>>>      /*
>>>>       * Debugfs
>>>>       */
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>>> new file mode 100644
>>>> index 000000000000..919d9d401750
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h
>>>> @@ -0,0 +1,51 @@
>>>> +/*
>>>> + * Copyright 2021 Advanced Micro Devices, Inc.
>>>> + *
>>>> + * Permission is hereby granted, free of charge, to any person obtaining a
>>>> + * copy of this software and associated documentation files (the "Software"),
>>>> + * to deal in the Software without restriction, including without limitation
>>>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>> + * Software is furnished to do so, subject to the following conditions:
>>>> + *
>>>> + * The above copyright notice and this permission notice shall be included in
>>>> + * all copies or substantial portions of the Software.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>>>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>>>> + * OTHER DEALINGS IN THE SOFTWARE.
>>>> + *
>>>> + */
>>>> +#include <linux/ioctl.h>
>>>> +
>>>> +/*
>>>> + * MMIO debugfs IOCTL structure
>>>> + */
>>>> +struct amdgpu_debugfs_regs2_iocdata {
>>>> +     __u32 use_srbm, use_grbm, pg_lock;
>>>> +     struct {
>>>> +             __u32 se, sh, instance;
>>>> +     } grbm;
>>>> +     struct {
>>>> +             __u32 me, pipe, queue, vmid;
>>>> +     } srbm;
>>>> +};
>>>> +
>>>> +/*
>>>> + * MMIO debugfs state data (per file* handle)
>>>> + */
>>>> +struct amdgpu_debugfs_regs2_data {
>>>> +     struct amdgpu_device *adev;
>>>> +     struct mutex lock;
>>>> +     struct amdgpu_debugfs_regs2_iocdata id;
>>>> +};
>>>> +
>>>> +enum AMDGPU_DEBUGFS_REGS2_CMDS {
>>>> +     AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0,
>>>> +};
>>>> +
>>>> +#define AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE _IOWR(0x20, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE, struct amdgpu_debugfs_regs2_iocdata)
>>>>


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-08-26 12:56 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-25 17:26 [PATCH] drm/amd/amdgpu: New debugfs interface for MMIO registers (v5) Tom St Denis
2021-08-26  9:59 ` Christian König
2021-08-26 12:12 ` Lazar, Lijo
2021-08-26 12:15   ` StDenis, Tom
2021-08-26 12:19     ` Lazar, Lijo
2021-08-26 12:22       ` StDenis, Tom
2021-08-26 12:26         ` Lazar, Lijo
2021-08-26 12:28           ` StDenis, Tom
2021-08-26 12:56             ` Christian König

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.