diff mbox series

[v4,11/14] drm/amdgpu: Guard against write accesses after device removal

Message ID 1611003683-3534-12-git-send-email-andrey.grodzovsky@amd.com (mailing list archive)
State New, archived
Headers show
Series RFC Support hot device unplug in amdgpu | expand

Commit Message

Andrey Grodzovsky Jan. 18, 2021, 9:01 p.m. UTC
This should prevent writing to memory or IO ranges possibly
already allocated for other uses after our device is removed.

Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
 drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
 drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
 drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
 9 files changed, 184 insertions(+), 89 deletions(-)

Comments

Christian König Jan. 19, 2021, 8:55 a.m. UTC | #1
Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
> This should prevent writing to memory or IO ranges possibly
> already allocated for other uses after our device is removed.

Wow, that adds quite some overhead to every register access. I'm not 
sure we can do this.

Christian.

>
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 ++++++++++++++++++++++++++++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
>   drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>   drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>   drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>   9 files changed, 184 insertions(+), 89 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index e99f4f1..0a9d73c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -72,6 +72,8 @@
>   
>   #include <linux/iommu.h>
>   
> +#include <drm/drm_drv.h>
> +
>   MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>   MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>   MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset)
>    */
>   void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value)
>   {
> +	int idx;
> +
>   	if (adev->in_pci_err_recovery)
>   		return;
>   
> +
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
> +
>   	if (offset < adev->rmmio_size)
>   		writeb(value, adev->rmmio + offset);
>   	else
>   		BUG();
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /**
> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>   			uint32_t reg, uint32_t v,
>   			uint32_t acc_flags)
>   {
> +	int idx;
> +
>   	if (adev->in_pci_err_recovery)
>   		return;
>   
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
> +
>   	if ((reg * 4) < adev->rmmio_size) {
>   		if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>   		    amdgpu_sriov_runtime(adev) &&
> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>   	}
>   
>   	trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /*
> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>   void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>   			     uint32_t reg, uint32_t v)
>   {
> +	int idx;
> +
>   	if (adev->in_pci_err_recovery)
>   		return;
>   
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
> +
>   	if (amdgpu_sriov_fullaccess(adev) &&
>   	    adev->gfx.rlc.funcs &&
>   	    adev->gfx.rlc.funcs->is_rlcg_access_range) {
> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>   	} else {
>   		writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>   	}
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /**
> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg)
>    */
>   void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>   {
> +	int idx;
> +
>   	if (adev->in_pci_err_recovery)
>   		return;
>   
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
> +
>   	if ((reg * 4) < adev->rio_mem_size)
>   		iowrite32(v, adev->rio_mem + (reg * 4));
>   	else {
>   		iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>   		iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>   	}
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /**
> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index)
>    */
>   void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
>   {
> +	int idx;
> +
>   	if (adev->in_pci_err_recovery)
>   		return;
>   
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
> +
>   	if (index < adev->doorbell.num_doorbells) {
>   		writel(v, adev->doorbell.ptr + index);
>   	} else {
>   		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>   	}
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /**
> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index)
>    */
>   void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
>   {
> +	int idx;
> +
>   	if (adev->in_pci_err_recovery)
>   		return;
>   
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
> +
>   	if (index < adev->doorbell.num_doorbells) {
>   		atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
>   	} else {
>   		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>   	}
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /**
> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
>   	unsigned long flags;
>   	void __iomem *pcie_index_offset;
>   	void __iomem *pcie_data_offset;
> +	int idx;
> +
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
>   
>   	spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>   	pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
>   	writel(reg_data, pcie_data_offset);
>   	readl(pcie_data_offset);
>   	spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /**
> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device *adev,
>   	unsigned long flags;
>   	void __iomem *pcie_index_offset;
>   	void __iomem *pcie_data_offset;
> +	int idx;
> +
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return;
>   
>   	spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>   	pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device *adev,
>   	writel((u32)(reg_data >> 32), pcie_data_offset);
>   	readl(pcie_data_offset);
>   	spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
> +
> +	drm_dev_exit(idx);
>   }
>   
>   /**
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> index fe1a39f..1beb4e6 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> @@ -31,6 +31,8 @@
>   #include "amdgpu_ras.h"
>   #include "amdgpu_xgmi.h"
>   
> +#include <drm/drm_drv.h>
> +
>   /**
>    * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>    *
> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
>   {
>   	void __iomem *ptr = (void *)cpu_pt_addr;
>   	uint64_t value;
> +	int idx;
> +
> +	if (!drm_dev_enter(&adev->ddev, &idx))
> +		return 0;
>   
>   	/*
>   	 * The following is for PTE only. GART does not have PDEs.
> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
>   	value = addr & 0x0000FFFFFFFFF000ULL;
>   	value |= flags;
>   	writeq(value, ptr + (gpu_page_idx * 8));
> +
> +	drm_dev_exit(idx);
> +
>   	return 0;
>   }
>   
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> index 523d22d..89e2bfe 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> @@ -37,6 +37,8 @@
>   
>   #include "amdgpu_ras.h"
>   
> +#include <drm/drm_drv.h>
> +
>   static int psp_sysfs_init(struct amdgpu_device *adev);
>   static void psp_sysfs_fini(struct amdgpu_device *adev);
>   
> @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>   		   struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>   {
>   	int ret;
> -	int index;
> +	int index, idx;
>   	int timeout = 2000;
>   	bool ras_intr = false;
>   	bool skip_unsupport = false;
> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>   	if (psp->adev->in_pci_err_recovery)
>   		return 0;
>   
> +	if (!drm_dev_enter(&psp->adev->ddev, &idx))
> +		return 0;
> +
>   	mutex_lock(&psp->mutex);
>   
>   	memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>   	ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index);
>   	if (ret) {
>   		atomic_dec(&psp->fence_value);
> -		mutex_unlock(&psp->mutex);
> -		return ret;
> +		goto exit;
>   	}
>   
>   	amdgpu_asic_invalidate_hdp(psp->adev, NULL);
> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>   			 psp->cmd_buf_mem->cmd_id,
>   			 psp->cmd_buf_mem->resp.status);
>   		if (!timeout) {
> -			mutex_unlock(&psp->mutex);
> -			return -EINVAL;
> +			ret = -EINVAL;
> +			goto exit;
>   		}
>   	}
>   
> @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>   		ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>   		ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>   	}
> -	mutex_unlock(&psp->mutex);
>   
> +exit:
> +	mutex_unlock(&psp->mutex);
> +	drm_dev_exit(idx);
>   	return ret;
>   }
>   
> @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
>   	if (!cmd)
>   		return -ENOMEM;
>   	/* Copy toc to psp firmware private buffer */
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -	memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
> +	psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>   
>   	psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size);
>   
> @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
>   	if (!cmd)
>   		return -ENOMEM;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -	memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
> +	psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>   
>   	psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>   				  psp->asd_ucode_size);
> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>   	if (!cmd)
>   		return -ENOMEM;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -	memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
> +	psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>   
>   	psp_prep_ta_load_cmd_buf(cmd,
>   				 psp->fw_pri_mc_addr,
> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>   	if (!cmd)
>   		return -ENOMEM;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -	memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
> +	psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>   
>   	psp_prep_ta_load_cmd_buf(cmd,
>   				 psp->fw_pri_mc_addr,
> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
>   	if (!cmd)
>   		return -ENOMEM;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -	memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
> +	psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>   	       psp->ta_hdcp_ucode_size);
>   
>   	psp_prep_ta_load_cmd_buf(cmd,
> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
>   	if (!cmd)
>   		return -ENOMEM;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -	memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
> +	psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>   
>   	psp_prep_ta_load_cmd_buf(cmd,
>   				 psp->fw_pri_mc_addr,
> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
>   	if (!cmd)
>   		return -ENOMEM;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -	memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
> +	psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>   
>   	psp_prep_ta_load_cmd_buf(cmd,
>   				 psp->fw_pri_mc_addr,
> @@ -2778,6 +2777,20 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
>   	return count;
>   }
>   
> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size)
> +{
> +	int idx;
> +
> +	if (!drm_dev_enter(&psp->adev->ddev, &idx))
> +		return;
> +
> +	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> +	memcpy(psp->fw_pri_buf, start_addr, bin_size);
> +
> +	drm_dev_exit(idx);
> +}
> +
> +
>   static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>   		   psp_usbc_pd_fw_sysfs_read,
>   		   psp_usbc_pd_fw_sysfs_write);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> index da250bc..ac69314 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
>   			  const char *chip_name);
>   int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>   					uint64_t *output_ptr);
> +
> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size);
> +
>   #endif
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> index 1a612f5..d656494 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> @@ -35,6 +35,8 @@
>   #include "amdgpu.h"
>   #include "atom.h"
>   
> +#include <drm/drm_drv.h>
> +
>   /*
>    * Rings
>    * Most engines on the GPU are fed via ring buffers.  Ring
> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
>   	ring->sched.ready = !r;
>   	return r;
>   }
> +
> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
> +{
> +	int idx;
> +	int i = 0;
> +
> +	if (!drm_dev_enter(&ring->adev->ddev, &idx))
> +		return;
> +
> +	while (i <= ring->buf_mask)
> +		ring->ring[i++] = ring->funcs->nop;
> +
> +	drm_dev_exit(idx);
> +
> +}
> +
> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
> +{
> +	int idx;
> +
> +	if (!drm_dev_enter(&ring->adev->ddev, &idx))
> +		return;
> +
> +	if (ring->count_dw <= 0)
> +		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> +	ring->ring[ring->wptr++ & ring->buf_mask] = v;
> +	ring->wptr &= ring->ptr_mask;
> +	ring->count_dw--;
> +
> +	drm_dev_exit(idx);
> +}
> +
> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
> +					      void *src, int count_dw)
> +{
> +	unsigned occupied, chunk1, chunk2;
> +	void *dst;
> +	int idx;
> +
> +	if (!drm_dev_enter(&ring->adev->ddev, &idx))
> +		return;
> +
> +	if (unlikely(ring->count_dw < count_dw))
> +		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> +
> +	occupied = ring->wptr & ring->buf_mask;
> +	dst = (void *)&ring->ring[occupied];
> +	chunk1 = ring->buf_mask + 1 - occupied;
> +	chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
> +	chunk2 = count_dw - chunk1;
> +	chunk1 <<= 2;
> +	chunk2 <<= 2;
> +
> +	if (chunk1)
> +		memcpy(dst, src, chunk1);
> +
> +	if (chunk2) {
> +		src += chunk1;
> +		dst = (void *)ring->ring;
> +		memcpy(dst, src, chunk2);
> +	}
> +
> +	ring->wptr += count_dw;
> +	ring->wptr &= ring->ptr_mask;
> +	ring->count_dw -= count_dw;
> +
> +	drm_dev_exit(idx);
> +}
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> index accb243..f90b81f 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> @@ -300,53 +300,12 @@ static inline void amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>   	*ring->cond_exe_cpu_addr = cond_exec;
>   }
>   
> -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
> -{
> -	int i = 0;
> -	while (i <= ring->buf_mask)
> -		ring->ring[i++] = ring->funcs->nop;
> -
> -}
> -
> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
> -{
> -	if (ring->count_dw <= 0)
> -		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> -	ring->ring[ring->wptr++ & ring->buf_mask] = v;
> -	ring->wptr &= ring->ptr_mask;
> -	ring->count_dw--;
> -}
> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>   
> -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
> -					      void *src, int count_dw)
> -{
> -	unsigned occupied, chunk1, chunk2;
> -	void *dst;
> -
> -	if (unlikely(ring->count_dw < count_dw))
> -		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> -
> -	occupied = ring->wptr & ring->buf_mask;
> -	dst = (void *)&ring->ring[occupied];
> -	chunk1 = ring->buf_mask + 1 - occupied;
> -	chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
> -	chunk2 = count_dw - chunk1;
> -	chunk1 <<= 2;
> -	chunk2 <<= 2;
> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>   
> -	if (chunk1)
> -		memcpy(dst, src, chunk1);
> -
> -	if (chunk2) {
> -		src += chunk1;
> -		dst = (void *)ring->ring;
> -		memcpy(dst, src, chunk2);
> -	}
> -
> -	ring->wptr += count_dw;
> -	ring->wptr &= ring->ptr_mask;
> -	ring->count_dw -= count_dw;
> -}
> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
> +					      void *src, int count_dw);
>   
>   int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>   
> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> index bd4248c..b3ce5be 100644
> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy PSP KDB binary to memory */
> -	memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
> +	psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>   
>   	/* Provide the PSP KDB to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy PSP SPL binary to memory */
> -	memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
> +	psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>   
>   	/* Provide the PSP SPL to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> @@ -335,10 +331,8 @@ static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy PSP System Driver binary to memory */
> -	memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
> +	psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>   
>   	/* Provide the sys driver to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy Secure OS binary to PSP memory */
> -	memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
> +	psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>   
>   	/* Provide the PSP secure OS to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
> index c4828bd..618e5b6 100644
> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
> @@ -138,10 +138,8 @@ static int psp_v12_0_bootloader_load_sysdrv(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy PSP System Driver binary to memory */
> -	memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
> +	psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>   
>   	/* Provide the sys driver to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy Secure OS binary to PSP memory */
> -	memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
> +	psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>   
>   	/* Provide the PSP secure OS to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
> index f2e725f..d0a6cccd 100644
> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
> @@ -102,10 +102,8 @@ static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy PSP System Driver binary to memory */
> -	memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
> +	psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>   
>   	/* Provide the sys driver to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
>   	if (ret)
>   		return ret;
>   
> -	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> -
>   	/* Copy Secure OS binary to PSP memory */
> -	memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
> +	psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>   
>   	/* Provide the PSP secure OS to bootloader */
>   	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
Andrey Grodzovsky Jan. 19, 2021, 3:35 p.m. UTC | #2
There is really no other way according to this article 
https://lwn.net/Articles/767885/

"A perfect solution seems nearly impossible though; we cannot acquire a mutex on 
the user
to prevent them from yanking a device and we cannot check for a presence change 
after every
device access for performance reasons. "

But I assumed srcu_read_lock should be pretty seamless performance wise, no ?
The other solution would be as I suggested to keep all the device IO ranges 
reserved and system
memory pages unfreed until the device is finalized in the driver but Daniel said 
this would upset the PCI layer (the MMIO ranges reservation part).

Andrey




On 1/19/21 3:55 AM, Christian König wrote:
> Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
>> This should prevent writing to memory or IO ranges possibly
>> already allocated for other uses after our device is removed.
>
> Wow, that adds quite some overhead to every register access. I'm not sure we 
> can do this.
>
> Christian.
>
>>
>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>> ---
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 ++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
>>   drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>>   drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>>   drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>>   9 files changed, 184 insertions(+), 89 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>> index e99f4f1..0a9d73c 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>> @@ -72,6 +72,8 @@
>>     #include <linux/iommu.h>
>>   +#include <drm/drm_drv.h>
>> +
>>   MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>>   MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>>   MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
>> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, 
>> uint32_t offset)
>>    */
>>   void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t 
>> value)
>>   {
>> +    int idx;
>> +
>>       if (adev->in_pci_err_recovery)
>>           return;
>>   +
>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>> +
>>       if (offset < adev->rmmio_size)
>>           writeb(value, adev->rmmio + offset);
>>       else
>>           BUG();
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /**
>> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>               uint32_t reg, uint32_t v,
>>               uint32_t acc_flags)
>>   {
>> +    int idx;
>> +
>>       if (adev->in_pci_err_recovery)
>>           return;
>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>> +
>>       if ((reg * 4) < adev->rmmio_size) {
>>           if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>>               amdgpu_sriov_runtime(adev) &&
>> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>       }
>>         trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /*
>> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>   void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>                    uint32_t reg, uint32_t v)
>>   {
>> +    int idx;
>> +
>>       if (adev->in_pci_err_recovery)
>>           return;
>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>> +
>>       if (amdgpu_sriov_fullaccess(adev) &&
>>           adev->gfx.rlc.funcs &&
>>           adev->gfx.rlc.funcs->is_rlcg_access_range) {
>> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>       } else {
>>           writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>>       }
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /**
>> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg)
>>    */
>>   void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>>   {
>> +    int idx;
>> +
>>       if (adev->in_pci_err_recovery)
>>           return;
>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>> +
>>       if ((reg * 4) < adev->rio_mem_size)
>>           iowrite32(v, adev->rio_mem + (reg * 4));
>>       else {
>>           iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>>           iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>>       }
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /**
>> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 
>> index)
>>    */
>>   void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
>>   {
>> +    int idx;
>> +
>>       if (adev->in_pci_err_recovery)
>>           return;
>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>> +
>>       if (index < adev->doorbell.num_doorbells) {
>>           writel(v, adev->doorbell.ptr + index);
>>       } else {
>>           DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>       }
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /**
>> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, 
>> u32 index)
>>    */
>>   void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
>>   {
>> +    int idx;
>> +
>>       if (adev->in_pci_err_recovery)
>>           return;
>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>> +
>>       if (index < adev->doorbell.num_doorbells) {
>>           atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
>>       } else {
>>           DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>       }
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /**
>> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device 
>> *adev,
>>       unsigned long flags;
>>       void __iomem *pcie_index_offset;
>>       void __iomem *pcie_data_offset;
>> +    int idx;
>> +
>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>>         spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>       pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
>>       writel(reg_data, pcie_data_offset);
>>       readl(pcie_data_offset);
>>       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /**
>> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device 
>> *adev,
>>       unsigned long flags;
>>       void __iomem *pcie_index_offset;
>>       void __iomem *pcie_data_offset;
>> +    int idx;
>> +
>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return;
>>         spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>       pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device 
>> *adev,
>>       writel((u32)(reg_data >> 32), pcie_data_offset);
>>       readl(pcie_data_offset);
>>       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>> +
>> +    drm_dev_exit(idx);
>>   }
>>     /**
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>> index fe1a39f..1beb4e6 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>> @@ -31,6 +31,8 @@
>>   #include "amdgpu_ras.h"
>>   #include "amdgpu_xgmi.h"
>>   +#include <drm/drm_drv.h>
>> +
>>   /**
>>    * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>>    *
>> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, 
>> void *cpu_pt_addr,
>>   {
>>       void __iomem *ptr = (void *)cpu_pt_addr;
>>       uint64_t value;
>> +    int idx;
>> +
>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>> +        return 0;
>>         /*
>>        * The following is for PTE only. GART does not have PDEs.
>> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, 
>> void *cpu_pt_addr,
>>       value = addr & 0x0000FFFFFFFFF000ULL;
>>       value |= flags;
>>       writeq(value, ptr + (gpu_page_idx * 8));
>> +
>> +    drm_dev_exit(idx);
>> +
>>       return 0;
>>   }
>>   diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>> index 523d22d..89e2bfe 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>> @@ -37,6 +37,8 @@
>>     #include "amdgpu_ras.h"
>>   +#include <drm/drm_drv.h>
>> +
>>   static int psp_sysfs_init(struct amdgpu_device *adev);
>>   static void psp_sysfs_fini(struct amdgpu_device *adev);
>>   @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>              struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>>   {
>>       int ret;
>> -    int index;
>> +    int index, idx;
>>       int timeout = 2000;
>>       bool ras_intr = false;
>>       bool skip_unsupport = false;
>> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>       if (psp->adev->in_pci_err_recovery)
>>           return 0;
>>   +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>> +        return 0;
>> +
>>       mutex_lock(&psp->mutex);
>>         memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
>> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>       ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, 
>> index);
>>       if (ret) {
>>           atomic_dec(&psp->fence_value);
>> -        mutex_unlock(&psp->mutex);
>> -        return ret;
>> +        goto exit;
>>       }
>>         amdgpu_asic_invalidate_hdp(psp->adev, NULL);
>> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>                psp->cmd_buf_mem->cmd_id,
>>                psp->cmd_buf_mem->resp.status);
>>           if (!timeout) {
>> -            mutex_unlock(&psp->mutex);
>> -            return -EINVAL;
>> +            ret = -EINVAL;
>> +            goto exit;
>>           }
>>       }
>>   @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>           ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>>           ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>>       }
>> -    mutex_unlock(&psp->mutex);
>>   +exit:
>> +    mutex_unlock(&psp->mutex);
>> +    drm_dev_exit(idx);
>>       return ret;
>>   }
>>   @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
>>       if (!cmd)
>>           return -ENOMEM;
>>       /* Copy toc to psp firmware private buffer */
>> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
>> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>>         psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size);
>>   @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
>>       if (!cmd)
>>           return -ENOMEM;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
>> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>>         psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>>                     psp->asd_ucode_size);
>> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>>       if (!cmd)
>>           return -ENOMEM;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>>         psp_prep_ta_load_cmd_buf(cmd,
>>                    psp->fw_pri_mc_addr,
>> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>>       if (!cmd)
>>           return -ENOMEM;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>> +    psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>>         psp_prep_ta_load_cmd_buf(cmd,
>>                    psp->fw_pri_mc_addr,
>> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
>>       if (!cmd)
>>           return -ENOMEM;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
>> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>>              psp->ta_hdcp_ucode_size);
>>         psp_prep_ta_load_cmd_buf(cmd,
>> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
>>       if (!cmd)
>>           return -ENOMEM;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>>         psp_prep_ta_load_cmd_buf(cmd,
>>                    psp->fw_pri_mc_addr,
>> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
>>       if (!cmd)
>>           return -ENOMEM;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>> +    psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>>         psp_prep_ta_load_cmd_buf(cmd,
>>                    psp->fw_pri_mc_addr,
>> @@ -2778,6 +2777,20 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct 
>> device *dev,
>>       return count;
>>   }
>>   +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t 
>> bin_size)
>> +{
>> +    int idx;
>> +
>> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>> +        return;
>> +
>> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
>> +
>> +    drm_dev_exit(idx);
>> +}
>> +
>> +
>>   static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>>              psp_usbc_pd_fw_sysfs_read,
>>              psp_usbc_pd_fw_sysfs_write);
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>> index da250bc..ac69314 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
>>                 const char *chip_name);
>>   int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>>                       uint64_t *output_ptr);
>> +
>> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t 
>> bin_size);
>> +
>>   #endif
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>> index 1a612f5..d656494 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>> @@ -35,6 +35,8 @@
>>   #include "amdgpu.h"
>>   #include "atom.h"
>>   +#include <drm/drm_drv.h>
>> +
>>   /*
>>    * Rings
>>    * Most engines on the GPU are fed via ring buffers.  Ring
>> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
>>       ring->sched.ready = !r;
>>       return r;
>>   }
>> +
>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>> +{
>> +    int idx;
>> +    int i = 0;
>> +
>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>> +        return;
>> +
>> +    while (i <= ring->buf_mask)
>> +        ring->ring[i++] = ring->funcs->nop;
>> +
>> +    drm_dev_exit(idx);
>> +
>> +}
>> +
>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>> +{
>> +    int idx;
>> +
>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>> +        return;
>> +
>> +    if (ring->count_dw <= 0)
>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>> +    ring->wptr &= ring->ptr_mask;
>> +    ring->count_dw--;
>> +
>> +    drm_dev_exit(idx);
>> +}
>> +
>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>> +                          void *src, int count_dw)
>> +{
>> +    unsigned occupied, chunk1, chunk2;
>> +    void *dst;
>> +    int idx;
>> +
>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>> +        return;
>> +
>> +    if (unlikely(ring->count_dw < count_dw))
>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>> +
>> +    occupied = ring->wptr & ring->buf_mask;
>> +    dst = (void *)&ring->ring[occupied];
>> +    chunk1 = ring->buf_mask + 1 - occupied;
>> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>> +    chunk2 = count_dw - chunk1;
>> +    chunk1 <<= 2;
>> +    chunk2 <<= 2;
>> +
>> +    if (chunk1)
>> +        memcpy(dst, src, chunk1);
>> +
>> +    if (chunk2) {
>> +        src += chunk1;
>> +        dst = (void *)ring->ring;
>> +        memcpy(dst, src, chunk2);
>> +    }
>> +
>> +    ring->wptr += count_dw;
>> +    ring->wptr &= ring->ptr_mask;
>> +    ring->count_dw -= count_dw;
>> +
>> +    drm_dev_exit(idx);
>> +}
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>> index accb243..f90b81f 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>> @@ -300,53 +300,12 @@ static inline void 
>> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>>       *ring->cond_exe_cpu_addr = cond_exec;
>>   }
>>   -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>> -{
>> -    int i = 0;
>> -    while (i <= ring->buf_mask)
>> -        ring->ring[i++] = ring->funcs->nop;
>> -
>> -}
>> -
>> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>> -{
>> -    if (ring->count_dw <= 0)
>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>> -    ring->wptr &= ring->ptr_mask;
>> -    ring->count_dw--;
>> -}
>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>>   -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>> -                          void *src, int count_dw)
>> -{
>> -    unsigned occupied, chunk1, chunk2;
>> -    void *dst;
>> -
>> -    if (unlikely(ring->count_dw < count_dw))
>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>> -
>> -    occupied = ring->wptr & ring->buf_mask;
>> -    dst = (void *)&ring->ring[occupied];
>> -    chunk1 = ring->buf_mask + 1 - occupied;
>> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>> -    chunk2 = count_dw - chunk1;
>> -    chunk1 <<= 2;
>> -    chunk2 <<= 2;
>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>>   -    if (chunk1)
>> -        memcpy(dst, src, chunk1);
>> -
>> -    if (chunk2) {
>> -        src += chunk1;
>> -        dst = (void *)ring->ring;
>> -        memcpy(dst, src, chunk2);
>> -    }
>> -
>> -    ring->wptr += count_dw;
>> -    ring->wptr &= ring->ptr_mask;
>> -    ring->count_dw -= count_dw;
>> -}
>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>> +                          void *src, int count_dw);
>>     int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>>   diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c 
>> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> index bd4248c..b3ce5be 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy PSP KDB binary to memory */
>> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
>> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>>         /* Provide the PSP KDB to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy PSP SPL binary to memory */
>> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
>> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>>         /* Provide the PSP SPL to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>> @@ -335,10 +331,8 @@ static int psp_v11_0_bootloader_load_sysdrv(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy PSP System Driver binary to memory */
>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>         /* Provide the sys driver to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy Secure OS binary to PSP memory */
>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>         /* Provide the PSP secure OS to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c 
>> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>> index c4828bd..618e5b6 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>> @@ -138,10 +138,8 @@ static int psp_v12_0_bootloader_load_sysdrv(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy PSP System Driver binary to memory */
>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>         /* Provide the sys driver to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy Secure OS binary to PSP memory */
>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>         /* Provide the PSP secure OS to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c 
>> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>> index f2e725f..d0a6cccd 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>> @@ -102,10 +102,8 @@ static int psp_v3_1_bootloader_load_sysdrv(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy PSP System Driver binary to memory */
>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>         /* Provide the sys driver to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct 
>> psp_context *psp)
>>       if (ret)
>>           return ret;
>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>> -
>>       /* Copy Secure OS binary to PSP memory */
>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>         /* Provide the PSP secure OS to bootloader */
>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>
Christian König Jan. 19, 2021, 3:39 p.m. UTC | #3
The is also the possibility to have the drm_dev_enter/exit much more 
high level.

E.g. we should it have anyway on every IOCTL and what remains are work 
items, scheduler threads and interrupts.

Christian.

Am 19.01.21 um 16:35 schrieb Andrey Grodzovsky:
> There is really no other way according to this article 
> https://lwn.net/Articles/767885/
>
> "A perfect solution seems nearly impossible though; we cannot acquire 
> a mutex on the user
> to prevent them from yanking a device and we cannot check for a 
> presence change after every
> device access for performance reasons. "
>
> But I assumed srcu_read_lock should be pretty seamless performance 
> wise, no ?
> The other solution would be as I suggested to keep all the device IO 
> ranges reserved and system
> memory pages unfreed until the device is finalized in the driver but 
> Daniel said this would upset the PCI layer (the MMIO ranges 
> reservation part).
>
> Andrey
>
>
>
>
> On 1/19/21 3:55 AM, Christian König wrote:
>> Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
>>> This should prevent writing to memory or IO ranges possibly
>>> already allocated for other uses after our device is removed.
>>
>> Wow, that adds quite some overhead to every register access. I'm not 
>> sure we can do this.
>>
>> Christian.
>>
>>>
>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>>> ---
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 
>>> ++++++++++++++++++++++++
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 
>>> +++++++++++++---------
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 
>>> ++++++++++++++++++++++++++++++
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
>>>   drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>>>   drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>>>   drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>>>   9 files changed, 184 insertions(+), 89 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> index e99f4f1..0a9d73c 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> @@ -72,6 +72,8 @@
>>>     #include <linux/iommu.h>
>>>   +#include <drm/drm_drv.h>
>>> +
>>>   MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>>>   MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>>>   MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
>>> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device 
>>> *adev, uint32_t offset)
>>>    */
>>>   void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, 
>>> uint8_t value)
>>>   {
>>> +    int idx;
>>> +
>>>       if (adev->in_pci_err_recovery)
>>>           return;
>>>   +
>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>> +
>>>       if (offset < adev->rmmio_size)
>>>           writeb(value, adev->rmmio + offset);
>>>       else
>>>           BUG();
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /**
>>> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device 
>>> *adev,
>>>               uint32_t reg, uint32_t v,
>>>               uint32_t acc_flags)
>>>   {
>>> +    int idx;
>>> +
>>>       if (adev->in_pci_err_recovery)
>>>           return;
>>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>> +
>>>       if ((reg * 4) < adev->rmmio_size) {
>>>           if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>>>               amdgpu_sriov_runtime(adev) &&
>>> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>       }
>>>         trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /*
>>> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device 
>>> *adev,
>>>   void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>                    uint32_t reg, uint32_t v)
>>>   {
>>> +    int idx;
>>> +
>>>       if (adev->in_pci_err_recovery)
>>>           return;
>>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>> +
>>>       if (amdgpu_sriov_fullaccess(adev) &&
>>>           adev->gfx.rlc.funcs &&
>>>           adev->gfx.rlc.funcs->is_rlcg_access_range) {
>>> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct 
>>> amdgpu_device *adev,
>>>       } else {
>>>           writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>>>       }
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /**
>>> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, 
>>> u32 reg)
>>>    */
>>>   void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>>>   {
>>> +    int idx;
>>> +
>>>       if (adev->in_pci_err_recovery)
>>>           return;
>>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>> +
>>>       if ((reg * 4) < adev->rio_mem_size)
>>>           iowrite32(v, adev->rio_mem + (reg * 4));
>>>       else {
>>>           iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>>>           iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>>>       }
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /**
>>> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device 
>>> *adev, u32 index)
>>>    */
>>>   void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, 
>>> u32 v)
>>>   {
>>> +    int idx;
>>> +
>>>       if (adev->in_pci_err_recovery)
>>>           return;
>>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>> +
>>>       if (index < adev->doorbell.num_doorbells) {
>>>           writel(v, adev->doorbell.ptr + index);
>>>       } else {
>>>           DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", 
>>> index);
>>>       }
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /**
>>> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device 
>>> *adev, u32 index)
>>>    */
>>>   void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, 
>>> u64 v)
>>>   {
>>> +    int idx;
>>> +
>>>       if (adev->in_pci_err_recovery)
>>>           return;
>>>   +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>> +
>>>       if (index < adev->doorbell.num_doorbells) {
>>>           atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
>>>       } else {
>>>           DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", 
>>> index);
>>>       }
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /**
>>> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct 
>>> amdgpu_device *adev,
>>>       unsigned long flags;
>>>       void __iomem *pcie_index_offset;
>>>       void __iomem *pcie_data_offset;
>>> +    int idx;
>>> +
>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>>         spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>       pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct 
>>> amdgpu_device *adev,
>>>       writel(reg_data, pcie_data_offset);
>>>       readl(pcie_data_offset);
>>>       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /**
>>> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct 
>>> amdgpu_device *adev,
>>>       unsigned long flags;
>>>       void __iomem *pcie_index_offset;
>>>       void __iomem *pcie_data_offset;
>>> +    int idx;
>>> +
>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return;
>>>         spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>       pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct 
>>> amdgpu_device *adev,
>>>       writel((u32)(reg_data >> 32), pcie_data_offset);
>>>       readl(pcie_data_offset);
>>>       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>> +
>>> +    drm_dev_exit(idx);
>>>   }
>>>     /**
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c 
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>> index fe1a39f..1beb4e6 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>> @@ -31,6 +31,8 @@
>>>   #include "amdgpu_ras.h"
>>>   #include "amdgpu_xgmi.h"
>>>   +#include <drm/drm_drv.h>
>>> +
>>>   /**
>>>    * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>>>    *
>>> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device 
>>> *adev, void *cpu_pt_addr,
>>>   {
>>>       void __iomem *ptr = (void *)cpu_pt_addr;
>>>       uint64_t value;
>>> +    int idx;
>>> +
>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>> +        return 0;
>>>         /*
>>>        * The following is for PTE only. GART does not have PDEs.
>>> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device 
>>> *adev, void *cpu_pt_addr,
>>>       value = addr & 0x0000FFFFFFFFF000ULL;
>>>       value |= flags;
>>>       writeq(value, ptr + (gpu_page_idx * 8));
>>> +
>>> +    drm_dev_exit(idx);
>>> +
>>>       return 0;
>>>   }
>>>   diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>> index 523d22d..89e2bfe 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>> @@ -37,6 +37,8 @@
>>>     #include "amdgpu_ras.h"
>>>   +#include <drm/drm_drv.h>
>>> +
>>>   static int psp_sysfs_init(struct amdgpu_device *adev);
>>>   static void psp_sysfs_fini(struct amdgpu_device *adev);
>>>   @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>              struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>>>   {
>>>       int ret;
>>> -    int index;
>>> +    int index, idx;
>>>       int timeout = 2000;
>>>       bool ras_intr = false;
>>>       bool skip_unsupport = false;
>>> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>       if (psp->adev->in_pci_err_recovery)
>>>           return 0;
>>>   +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>> +        return 0;
>>> +
>>>       mutex_lock(&psp->mutex);
>>>         memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
>>> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>       ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, 
>>> fence_mc_addr, index);
>>>       if (ret) {
>>>           atomic_dec(&psp->fence_value);
>>> -        mutex_unlock(&psp->mutex);
>>> -        return ret;
>>> +        goto exit;
>>>       }
>>>         amdgpu_asic_invalidate_hdp(psp->adev, NULL);
>>> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>                psp->cmd_buf_mem->cmd_id,
>>>                psp->cmd_buf_mem->resp.status);
>>>           if (!timeout) {
>>> -            mutex_unlock(&psp->mutex);
>>> -            return -EINVAL;
>>> +            ret = -EINVAL;
>>> +            goto exit;
>>>           }
>>>       }
>>>   @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>           ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>>>           ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>>>       }
>>> -    mutex_unlock(&psp->mutex);
>>>   +exit:
>>> +    mutex_unlock(&psp->mutex);
>>> +    drm_dev_exit(idx);
>>>       return ret;
>>>   }
>>>   @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
>>>       if (!cmd)
>>>           return -ENOMEM;
>>>       /* Copy toc to psp firmware private buffer */
>>> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
>>> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>>>         psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, 
>>> psp->toc_bin_size);
>>>   @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
>>>       if (!cmd)
>>>           return -ENOMEM;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
>>> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>>>         psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>>>                     psp->asd_ucode_size);
>>> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>>>       if (!cmd)
>>>           return -ENOMEM;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, 
>>> psp->ta_xgmi_ucode_size);
>>> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, 
>>> psp->ta_xgmi_ucode_size);
>>>         psp_prep_ta_load_cmd_buf(cmd,
>>>                    psp->fw_pri_mc_addr,
>>> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>>>       if (!cmd)
>>>           return -ENOMEM;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, 
>>> psp->ta_ras_ucode_size);
>>> +    psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>>>         psp_prep_ta_load_cmd_buf(cmd,
>>>                    psp->fw_pri_mc_addr,
>>> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
>>>       if (!cmd)
>>>           return -ENOMEM;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
>>> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>>>              psp->ta_hdcp_ucode_size);
>>>         psp_prep_ta_load_cmd_buf(cmd,
>>> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
>>>       if (!cmd)
>>>           return -ENOMEM;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, 
>>> psp->ta_dtm_ucode_size);
>>> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>>>         psp_prep_ta_load_cmd_buf(cmd,
>>>                    psp->fw_pri_mc_addr,
>>> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
>>>       if (!cmd)
>>>           return -ENOMEM;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, 
>>> psp->ta_rap_ucode_size);
>>> +    psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>>>         psp_prep_ta_load_cmd_buf(cmd,
>>>                    psp->fw_pri_mc_addr,
>>> @@ -2778,6 +2777,20 @@ static ssize_t 
>>> psp_usbc_pd_fw_sysfs_write(struct device *dev,
>>>       return count;
>>>   }
>>>   +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, 
>>> uint32_t bin_size)
>>> +{
>>> +    int idx;
>>> +
>>> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>> +        return;
>>> +
>>> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
>>> +
>>> +    drm_dev_exit(idx);
>>> +}
>>> +
>>> +
>>>   static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>>>              psp_usbc_pd_fw_sysfs_read,
>>>              psp_usbc_pd_fw_sysfs_write);
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h 
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>> index da250bc..ac69314 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
>>>                 const char *chip_name);
>>>   int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>>>                       uint64_t *output_ptr);
>>> +
>>> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, 
>>> uint32_t bin_size);
>>> +
>>>   #endif
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c 
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>> index 1a612f5..d656494 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>> @@ -35,6 +35,8 @@
>>>   #include "amdgpu.h"
>>>   #include "atom.h"
>>>   +#include <drm/drm_drv.h>
>>> +
>>>   /*
>>>    * Rings
>>>    * Most engines on the GPU are fed via ring buffers.  Ring
>>> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring 
>>> *ring)
>>>       ring->sched.ready = !r;
>>>       return r;
>>>   }
>>> +
>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>> +{
>>> +    int idx;
>>> +    int i = 0;
>>> +
>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>> +        return;
>>> +
>>> +    while (i <= ring->buf_mask)
>>> +        ring->ring[i++] = ring->funcs->nop;
>>> +
>>> +    drm_dev_exit(idx);
>>> +
>>> +}
>>> +
>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>> +{
>>> +    int idx;
>>> +
>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>> +        return;
>>> +
>>> +    if (ring->count_dw <= 0)
>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>> expected!\n");
>>> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>> +    ring->wptr &= ring->ptr_mask;
>>> +    ring->count_dw--;
>>> +
>>> +    drm_dev_exit(idx);
>>> +}
>>> +
>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>> +                          void *src, int count_dw)
>>> +{
>>> +    unsigned occupied, chunk1, chunk2;
>>> +    void *dst;
>>> +    int idx;
>>> +
>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>> +        return;
>>> +
>>> +    if (unlikely(ring->count_dw < count_dw))
>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>> expected!\n");
>>> +
>>> +    occupied = ring->wptr & ring->buf_mask;
>>> +    dst = (void *)&ring->ring[occupied];
>>> +    chunk1 = ring->buf_mask + 1 - occupied;
>>> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>> +    chunk2 = count_dw - chunk1;
>>> +    chunk1 <<= 2;
>>> +    chunk2 <<= 2;
>>> +
>>> +    if (chunk1)
>>> +        memcpy(dst, src, chunk1);
>>> +
>>> +    if (chunk2) {
>>> +        src += chunk1;
>>> +        dst = (void *)ring->ring;
>>> +        memcpy(dst, src, chunk2);
>>> +    }
>>> +
>>> +    ring->wptr += count_dw;
>>> +    ring->wptr &= ring->ptr_mask;
>>> +    ring->count_dw -= count_dw;
>>> +
>>> +    drm_dev_exit(idx);
>>> +}
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h 
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>> index accb243..f90b81f 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>> @@ -300,53 +300,12 @@ static inline void 
>>> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>>>       *ring->cond_exe_cpu_addr = cond_exec;
>>>   }
>>>   -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>> -{
>>> -    int i = 0;
>>> -    while (i <= ring->buf_mask)
>>> -        ring->ring[i++] = ring->funcs->nop;
>>> -
>>> -}
>>> -
>>> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, 
>>> uint32_t v)
>>> -{
>>> -    if (ring->count_dw <= 0)
>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>> expected!\n");
>>> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>> -    ring->wptr &= ring->ptr_mask;
>>> -    ring->count_dw--;
>>> -}
>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>>>   -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring 
>>> *ring,
>>> -                          void *src, int count_dw)
>>> -{
>>> -    unsigned occupied, chunk1, chunk2;
>>> -    void *dst;
>>> -
>>> -    if (unlikely(ring->count_dw < count_dw))
>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>> expected!\n");
>>> -
>>> -    occupied = ring->wptr & ring->buf_mask;
>>> -    dst = (void *)&ring->ring[occupied];
>>> -    chunk1 = ring->buf_mask + 1 - occupied;
>>> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>> -    chunk2 = count_dw - chunk1;
>>> -    chunk1 <<= 2;
>>> -    chunk2 <<= 2;
>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>>>   -    if (chunk1)
>>> -        memcpy(dst, src, chunk1);
>>> -
>>> -    if (chunk2) {
>>> -        src += chunk1;
>>> -        dst = (void *)ring->ring;
>>> -        memcpy(dst, src, chunk2);
>>> -    }
>>> -
>>> -    ring->wptr += count_dw;
>>> -    ring->wptr &= ring->ptr_mask;
>>> -    ring->count_dw -= count_dw;
>>> -}
>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>> +                          void *src, int count_dw);
>>>     int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>>>   diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c 
>>> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>> index bd4248c..b3ce5be 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct 
>>> psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy PSP KDB binary to memory */
>>> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
>>> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>>>         /* Provide the PSP KDB to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct 
>>> psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy PSP SPL binary to memory */
>>> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
>>> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>>>         /* Provide the PSP SPL to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>> @@ -335,10 +331,8 @@ static int 
>>> psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy PSP System Driver binary to memory */
>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>         /* Provide the sys driver to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct 
>>> psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy Secure OS binary to PSP memory */
>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>         /* Provide the PSP secure OS to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c 
>>> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>> index c4828bd..618e5b6 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>> @@ -138,10 +138,8 @@ static int 
>>> psp_v12_0_bootloader_load_sysdrv(struct psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy PSP System Driver binary to memory */
>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>         /* Provide the sys driver to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct 
>>> psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy Secure OS binary to PSP memory */
>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>         /* Provide the PSP secure OS to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c 
>>> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>> index f2e725f..d0a6cccd 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>> @@ -102,10 +102,8 @@ static int 
>>> psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy PSP System Driver binary to memory */
>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>         /* Provide the sys driver to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct 
>>> psp_context *psp)
>>>       if (ret)
>>>           return ret;
>>>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>> -
>>>       /* Copy Secure OS binary to PSP memory */
>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>         /* Provide the PSP secure OS to bootloader */
>>>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>
Daniel Vetter Jan. 19, 2021, 6:05 p.m. UTC | #4
On Tue, Jan 19, 2021 at 4:35 PM Andrey Grodzovsky
<Andrey.Grodzovsky@amd.com> wrote:
>
> There is really no other way according to this article
> https://lwn.net/Articles/767885/
>
> "A perfect solution seems nearly impossible though; we cannot acquire a mutex on
> the user
> to prevent them from yanking a device and we cannot check for a presence change
> after every
> device access for performance reasons. "
>
> But I assumed srcu_read_lock should be pretty seamless performance wise, no ?

The read side is supposed to be dirt cheap, the write side is were we
just stall for all readers to eventually complete on their own.
Definitely should be much cheaper than mmio read, on the mmio write
side it might actually hurt a bit. Otoh I think those don't stall the
cpu by default when they're timing out, so maybe if the overhead is
too much for those, we could omit them?

Maybe just do a small microbenchmark for these for testing, with a
register that doesn't change hw state. So with and without
drm_dev_enter/exit, and also one with the hw plugged out so that we
have actual timeouts in the transactions.
-Daniel

> The other solution would be as I suggested to keep all the device IO ranges
> reserved and system
> memory pages unfreed until the device is finalized in the driver but Daniel said
> this would upset the PCI layer (the MMIO ranges reservation part).
>
> Andrey
>
>
>
>
> On 1/19/21 3:55 AM, Christian König wrote:
> > Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
> >> This should prevent writing to memory or IO ranges possibly
> >> already allocated for other uses after our device is removed.
> >
> > Wow, that adds quite some overhead to every register access. I'm not sure we
> > can do this.
> >
> > Christian.
> >
> >>
> >> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> >> ---
> >>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
> >>   drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
> >>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
> >>   drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
> >>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 ++++++++++++++++++++++++++++++
> >>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
> >>   drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
> >>   drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
> >>   drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
> >>   9 files changed, 184 insertions(+), 89 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> >> index e99f4f1..0a9d73c 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> >> @@ -72,6 +72,8 @@
> >>     #include <linux/iommu.h>
> >>   +#include <drm/drm_drv.h>
> >> +
> >>   MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
> >>   MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
> >>   MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
> >> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev,
> >> uint32_t offset)
> >>    */
> >>   void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t
> >> value)
> >>   {
> >> +    int idx;
> >> +
> >>       if (adev->in_pci_err_recovery)
> >>           return;
> >>   +
> >> +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >> +
> >>       if (offset < adev->rmmio_size)
> >>           writeb(value, adev->rmmio + offset);
> >>       else
> >>           BUG();
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /**
> >> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
> >>               uint32_t reg, uint32_t v,
> >>               uint32_t acc_flags)
> >>   {
> >> +    int idx;
> >> +
> >>       if (adev->in_pci_err_recovery)
> >>           return;
> >>   +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >> +
> >>       if ((reg * 4) < adev->rmmio_size) {
> >>           if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
> >>               amdgpu_sriov_runtime(adev) &&
> >> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
> >>       }
> >>         trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /*
> >> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
> >>   void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
> >>                    uint32_t reg, uint32_t v)
> >>   {
> >> +    int idx;
> >> +
> >>       if (adev->in_pci_err_recovery)
> >>           return;
> >>   +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >> +
> >>       if (amdgpu_sriov_fullaccess(adev) &&
> >>           adev->gfx.rlc.funcs &&
> >>           adev->gfx.rlc.funcs->is_rlcg_access_range) {
> >> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
> >>       } else {
> >>           writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
> >>       }
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /**
> >> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg)
> >>    */
> >>   void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
> >>   {
> >> +    int idx;
> >> +
> >>       if (adev->in_pci_err_recovery)
> >>           return;
> >>   +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >> +
> >>       if ((reg * 4) < adev->rio_mem_size)
> >>           iowrite32(v, adev->rio_mem + (reg * 4));
> >>       else {
> >>           iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
> >>           iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
> >>       }
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /**
> >> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32
> >> index)
> >>    */
> >>   void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
> >>   {
> >> +    int idx;
> >> +
> >>       if (adev->in_pci_err_recovery)
> >>           return;
> >>   +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >> +
> >>       if (index < adev->doorbell.num_doorbells) {
> >>           writel(v, adev->doorbell.ptr + index);
> >>       } else {
> >>           DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
> >>       }
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /**
> >> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev,
> >> u32 index)
> >>    */
> >>   void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
> >>   {
> >> +    int idx;
> >> +
> >>       if (adev->in_pci_err_recovery)
> >>           return;
> >>   +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >> +
> >>       if (index < adev->doorbell.num_doorbells) {
> >>           atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
> >>       } else {
> >>           DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
> >>       }
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /**
> >> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device
> >> *adev,
> >>       unsigned long flags;
> >>       void __iomem *pcie_index_offset;
> >>       void __iomem *pcie_data_offset;
> >> +    int idx;
> >> +
> >> +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >>         spin_lock_irqsave(&adev->pcie_idx_lock, flags);
> >>       pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
> >> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
> >>       writel(reg_data, pcie_data_offset);
> >>       readl(pcie_data_offset);
> >>       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /**
> >> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
> >> *adev,
> >>       unsigned long flags;
> >>       void __iomem *pcie_index_offset;
> >>       void __iomem *pcie_data_offset;
> >> +    int idx;
> >> +
> >> +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return;
> >>         spin_lock_irqsave(&adev->pcie_idx_lock, flags);
> >>       pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
> >> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
> >> *adev,
> >>       writel((u32)(reg_data >> 32), pcie_data_offset);
> >>       readl(pcie_data_offset);
> >>       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
> >> +
> >> +    drm_dev_exit(idx);
> >>   }
> >>     /**
> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> >> index fe1a39f..1beb4e6 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> >> @@ -31,6 +31,8 @@
> >>   #include "amdgpu_ras.h"
> >>   #include "amdgpu_xgmi.h"
> >>   +#include <drm/drm_drv.h>
> >> +
> >>   /**
> >>    * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
> >>    *
> >> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
> >> void *cpu_pt_addr,
> >>   {
> >>       void __iomem *ptr = (void *)cpu_pt_addr;
> >>       uint64_t value;
> >> +    int idx;
> >> +
> >> +    if (!drm_dev_enter(&adev->ddev, &idx))
> >> +        return 0;
> >>         /*
> >>        * The following is for PTE only. GART does not have PDEs.
> >> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
> >> void *cpu_pt_addr,
> >>       value = addr & 0x0000FFFFFFFFF000ULL;
> >>       value |= flags;
> >>       writeq(value, ptr + (gpu_page_idx * 8));
> >> +
> >> +    drm_dev_exit(idx);
> >> +
> >>       return 0;
> >>   }
> >>   diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> >> index 523d22d..89e2bfe 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> >> @@ -37,6 +37,8 @@
> >>     #include "amdgpu_ras.h"
> >>   +#include <drm/drm_drv.h>
> >> +
> >>   static int psp_sysfs_init(struct amdgpu_device *adev);
> >>   static void psp_sysfs_fini(struct amdgpu_device *adev);
> >>   @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
> >>              struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
> >>   {
> >>       int ret;
> >> -    int index;
> >> +    int index, idx;
> >>       int timeout = 2000;
> >>       bool ras_intr = false;
> >>       bool skip_unsupport = false;
> >> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
> >>       if (psp->adev->in_pci_err_recovery)
> >>           return 0;
> >>   +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
> >> +        return 0;
> >> +
> >>       mutex_lock(&psp->mutex);
> >>         memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
> >> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
> >>       ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr,
> >> index);
> >>       if (ret) {
> >>           atomic_dec(&psp->fence_value);
> >> -        mutex_unlock(&psp->mutex);
> >> -        return ret;
> >> +        goto exit;
> >>       }
> >>         amdgpu_asic_invalidate_hdp(psp->adev, NULL);
> >> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
> >>                psp->cmd_buf_mem->cmd_id,
> >>                psp->cmd_buf_mem->resp.status);
> >>           if (!timeout) {
> >> -            mutex_unlock(&psp->mutex);
> >> -            return -EINVAL;
> >> +            ret = -EINVAL;
> >> +            goto exit;
> >>           }
> >>       }
> >>   @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
> >>           ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
> >>           ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
> >>       }
> >> -    mutex_unlock(&psp->mutex);
> >>   +exit:
> >> +    mutex_unlock(&psp->mutex);
> >> +    drm_dev_exit(idx);
> >>       return ret;
> >>   }
> >>   @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
> >>       if (!cmd)
> >>           return -ENOMEM;
> >>       /* Copy toc to psp firmware private buffer */
> >> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
> >> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
> >>         psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size);
> >>   @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
> >>       if (!cmd)
> >>           return -ENOMEM;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
> >> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
> >>         psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
> >>                     psp->asd_ucode_size);
> >> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
> >>       if (!cmd)
> >>           return -ENOMEM;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
> >> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
> >>         psp_prep_ta_load_cmd_buf(cmd,
> >>                    psp->fw_pri_mc_addr,
> >> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
> >>       if (!cmd)
> >>           return -ENOMEM;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
> >> +    psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
> >>         psp_prep_ta_load_cmd_buf(cmd,
> >>                    psp->fw_pri_mc_addr,
> >> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
> >>       if (!cmd)
> >>           return -ENOMEM;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
> >> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
> >>              psp->ta_hdcp_ucode_size);
> >>         psp_prep_ta_load_cmd_buf(cmd,
> >> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
> >>       if (!cmd)
> >>           return -ENOMEM;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
> >> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
> >>         psp_prep_ta_load_cmd_buf(cmd,
> >>                    psp->fw_pri_mc_addr,
> >> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
> >>       if (!cmd)
> >>           return -ENOMEM;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
> >> +    psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
> >>         psp_prep_ta_load_cmd_buf(cmd,
> >>                    psp->fw_pri_mc_addr,
> >> @@ -2778,6 +2777,20 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct
> >> device *dev,
> >>       return count;
> >>   }
> >>   +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
> >> bin_size)
> >> +{
> >> +    int idx;
> >> +
> >> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
> >> +        return;
> >> +
> >> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
> >> +
> >> +    drm_dev_exit(idx);
> >> +}
> >> +
> >> +
> >>   static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
> >>              psp_usbc_pd_fw_sysfs_read,
> >>              psp_usbc_pd_fw_sysfs_write);
> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> >> index da250bc..ac69314 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> >> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
> >>                 const char *chip_name);
> >>   int psp_get_fw_attestation_records_addr(struct psp_context *psp,
> >>                       uint64_t *output_ptr);
> >> +
> >> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
> >> bin_size);
> >> +
> >>   #endif
> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> >> index 1a612f5..d656494 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> >> @@ -35,6 +35,8 @@
> >>   #include "amdgpu.h"
> >>   #include "atom.h"
> >>   +#include <drm/drm_drv.h>
> >> +
> >>   /*
> >>    * Rings
> >>    * Most engines on the GPU are fed via ring buffers.  Ring
> >> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
> >>       ring->sched.ready = !r;
> >>       return r;
> >>   }
> >> +
> >> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
> >> +{
> >> +    int idx;
> >> +    int i = 0;
> >> +
> >> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
> >> +        return;
> >> +
> >> +    while (i <= ring->buf_mask)
> >> +        ring->ring[i++] = ring->funcs->nop;
> >> +
> >> +    drm_dev_exit(idx);
> >> +
> >> +}
> >> +
> >> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
> >> +{
> >> +    int idx;
> >> +
> >> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
> >> +        return;
> >> +
> >> +    if (ring->count_dw <= 0)
> >> +        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> >> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
> >> +    ring->wptr &= ring->ptr_mask;
> >> +    ring->count_dw--;
> >> +
> >> +    drm_dev_exit(idx);
> >> +}
> >> +
> >> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
> >> +                          void *src, int count_dw)
> >> +{
> >> +    unsigned occupied, chunk1, chunk2;
> >> +    void *dst;
> >> +    int idx;
> >> +
> >> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
> >> +        return;
> >> +
> >> +    if (unlikely(ring->count_dw < count_dw))
> >> +        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> >> +
> >> +    occupied = ring->wptr & ring->buf_mask;
> >> +    dst = (void *)&ring->ring[occupied];
> >> +    chunk1 = ring->buf_mask + 1 - occupied;
> >> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
> >> +    chunk2 = count_dw - chunk1;
> >> +    chunk1 <<= 2;
> >> +    chunk2 <<= 2;
> >> +
> >> +    if (chunk1)
> >> +        memcpy(dst, src, chunk1);
> >> +
> >> +    if (chunk2) {
> >> +        src += chunk1;
> >> +        dst = (void *)ring->ring;
> >> +        memcpy(dst, src, chunk2);
> >> +    }
> >> +
> >> +    ring->wptr += count_dw;
> >> +    ring->wptr &= ring->ptr_mask;
> >> +    ring->count_dw -= count_dw;
> >> +
> >> +    drm_dev_exit(idx);
> >> +}
> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> >> index accb243..f90b81f 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> >> @@ -300,53 +300,12 @@ static inline void
> >> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
> >>       *ring->cond_exe_cpu_addr = cond_exec;
> >>   }
> >>   -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
> >> -{
> >> -    int i = 0;
> >> -    while (i <= ring->buf_mask)
> >> -        ring->ring[i++] = ring->funcs->nop;
> >> -
> >> -}
> >> -
> >> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
> >> -{
> >> -    if (ring->count_dw <= 0)
> >> -        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> >> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
> >> -    ring->wptr &= ring->ptr_mask;
> >> -    ring->count_dw--;
> >> -}
> >> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
> >>   -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
> >> -                          void *src, int count_dw)
> >> -{
> >> -    unsigned occupied, chunk1, chunk2;
> >> -    void *dst;
> >> -
> >> -    if (unlikely(ring->count_dw < count_dw))
> >> -        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
> >> -
> >> -    occupied = ring->wptr & ring->buf_mask;
> >> -    dst = (void *)&ring->ring[occupied];
> >> -    chunk1 = ring->buf_mask + 1 - occupied;
> >> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
> >> -    chunk2 = count_dw - chunk1;
> >> -    chunk1 <<= 2;
> >> -    chunk2 <<= 2;
> >> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
> >>   -    if (chunk1)
> >> -        memcpy(dst, src, chunk1);
> >> -
> >> -    if (chunk2) {
> >> -        src += chunk1;
> >> -        dst = (void *)ring->ring;
> >> -        memcpy(dst, src, chunk2);
> >> -    }
> >> -
> >> -    ring->wptr += count_dw;
> >> -    ring->wptr &= ring->ptr_mask;
> >> -    ring->count_dw -= count_dw;
> >> -}
> >> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
> >> +                          void *src, int count_dw);
> >>     int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
> >>   diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> >> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> >> index bd4248c..b3ce5be 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> >> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy PSP KDB binary to memory */
> >> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
> >> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
> >>         /* Provide the PSP KDB to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy PSP SPL binary to memory */
> >> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
> >> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
> >>         /* Provide the PSP SPL to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >> @@ -335,10 +331,8 @@ static int psp_v11_0_bootloader_load_sysdrv(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy PSP System Driver binary to memory */
> >> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
> >> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
> >>         /* Provide the sys driver to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy Secure OS binary to PSP memory */
> >> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
> >> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
> >>         /* Provide the PSP secure OS to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
> >> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
> >> index c4828bd..618e5b6 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
> >> @@ -138,10 +138,8 @@ static int psp_v12_0_bootloader_load_sysdrv(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy PSP System Driver binary to memory */
> >> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
> >> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
> >>         /* Provide the sys driver to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy Secure OS binary to PSP memory */
> >> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
> >> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
> >>         /* Provide the PSP secure OS to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
> >> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
> >> index f2e725f..d0a6cccd 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
> >> @@ -102,10 +102,8 @@ static int psp_v3_1_bootloader_load_sysdrv(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy PSP System Driver binary to memory */
> >> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
> >> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
> >>         /* Provide the sys driver to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct
> >> psp_context *psp)
> >>       if (ret)
> >>           return ret;
> >>   -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
> >> -
> >>       /* Copy Secure OS binary to PSP memory */
> >> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
> >> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
> >>         /* Provide the PSP secure OS to bootloader */
> >>       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
> >
Andrey Grodzovsky Jan. 19, 2021, 6:22 p.m. UTC | #5
On 1/19/21 1:05 PM, Daniel Vetter wrote:
> On Tue, Jan 19, 2021 at 4:35 PM Andrey Grodzovsky
> <Andrey.Grodzovsky@amd.com> wrote:
>> There is really no other way according to this article
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flwn.net%2FArticles%2F767885%2F&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7a1f5ae6a06f4661d47708d8bca4cb32%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466763278674162%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=QupsglO9WRuis8XRLBFIhl6miTXVOdAnk8oP4BfSclQ%3D&amp;reserved=0
>>
>> "A perfect solution seems nearly impossible though; we cannot acquire a mutex on
>> the user
>> to prevent them from yanking a device and we cannot check for a presence change
>> after every
>> device access for performance reasons. "
>>
>> But I assumed srcu_read_lock should be pretty seamless performance wise, no ?
> The read side is supposed to be dirt cheap, the write side is were we
> just stall for all readers to eventually complete on their own.
> Definitely should be much cheaper than mmio read, on the mmio write
> side it might actually hurt a bit. Otoh I think those don't stall the
> cpu by default when they're timing out, so maybe if the overhead is
> too much for those, we could omit them?
>
> Maybe just do a small microbenchmark for these for testing, with a
> register that doesn't change hw state. So with and without
> drm_dev_enter/exit, and also one with the hw plugged out so that we
> have actual timeouts in the transactions.
> -Daniel


So say writing in a loop to some harmless scratch register for many times both 
for plugged
and unplugged case and measure total time delta ?

Andrey


>
>> The other solution would be as I suggested to keep all the device IO ranges
>> reserved and system
>> memory pages unfreed until the device is finalized in the driver but Daniel said
>> this would upset the PCI layer (the MMIO ranges reservation part).
>>
>> Andrey
>>
>>
>>
>>
>> On 1/19/21 3:55 AM, Christian König wrote:
>>> Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
>>>> This should prevent writing to memory or IO ranges possibly
>>>> already allocated for other uses after our device is removed.
>>> Wow, that adds quite some overhead to every register access. I'm not sure we
>>> can do this.
>>>
>>> Christian.
>>>
>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>>>> ---
>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 ++++++++++++++++++++++++++++++
>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
>>>>    drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>>>>    drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>>>>    drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>>>>    9 files changed, 184 insertions(+), 89 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>> index e99f4f1..0a9d73c 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>> @@ -72,6 +72,8 @@
>>>>      #include <linux/iommu.h>
>>>>    +#include <drm/drm_drv.h>
>>>> +
>>>>    MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>>>>    MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>>>>    MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
>>>> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev,
>>>> uint32_t offset)
>>>>     */
>>>>    void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t
>>>> value)
>>>>    {
>>>> +    int idx;
>>>> +
>>>>        if (adev->in_pci_err_recovery)
>>>>            return;
>>>>    +
>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>>        if (offset < adev->rmmio_size)
>>>>            writeb(value, adev->rmmio + offset);
>>>>        else
>>>>            BUG();
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /**
>>>> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>                uint32_t reg, uint32_t v,
>>>>                uint32_t acc_flags)
>>>>    {
>>>> +    int idx;
>>>> +
>>>>        if (adev->in_pci_err_recovery)
>>>>            return;
>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>>        if ((reg * 4) < adev->rmmio_size) {
>>>>            if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>>>>                amdgpu_sriov_runtime(adev) &&
>>>> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>        }
>>>>          trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /*
>>>> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>    void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>                     uint32_t reg, uint32_t v)
>>>>    {
>>>> +    int idx;
>>>> +
>>>>        if (adev->in_pci_err_recovery)
>>>>            return;
>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>>        if (amdgpu_sriov_fullaccess(adev) &&
>>>>            adev->gfx.rlc.funcs &&
>>>>            adev->gfx.rlc.funcs->is_rlcg_access_range) {
>>>> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>        } else {
>>>>            writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>>>>        }
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /**
>>>> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg)
>>>>     */
>>>>    void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>>>>    {
>>>> +    int idx;
>>>> +
>>>>        if (adev->in_pci_err_recovery)
>>>>            return;
>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>>        if ((reg * 4) < adev->rio_mem_size)
>>>>            iowrite32(v, adev->rio_mem + (reg * 4));
>>>>        else {
>>>>            iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>>>>            iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>>>>        }
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /**
>>>> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32
>>>> index)
>>>>     */
>>>>    void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
>>>>    {
>>>> +    int idx;
>>>> +
>>>>        if (adev->in_pci_err_recovery)
>>>>            return;
>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>            writel(v, adev->doorbell.ptr + index);
>>>>        } else {
>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>        }
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /**
>>>> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev,
>>>> u32 index)
>>>>     */
>>>>    void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
>>>>    {
>>>> +    int idx;
>>>> +
>>>>        if (adev->in_pci_err_recovery)
>>>>            return;
>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>            atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
>>>>        } else {
>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>        }
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /**
>>>> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device
>>>> *adev,
>>>>        unsigned long flags;
>>>>        void __iomem *pcie_index_offset;
>>>>        void __iomem *pcie_data_offset;
>>>> +    int idx;
>>>> +
>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
>>>>        writel(reg_data, pcie_data_offset);
>>>>        readl(pcie_data_offset);
>>>>        spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /**
>>>> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
>>>> *adev,
>>>>        unsigned long flags;
>>>>        void __iomem *pcie_index_offset;
>>>>        void __iomem *pcie_data_offset;
>>>> +    int idx;
>>>> +
>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return;
>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
>>>> *adev,
>>>>        writel((u32)(reg_data >> 32), pcie_data_offset);
>>>>        readl(pcie_data_offset);
>>>>        spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>> +
>>>> +    drm_dev_exit(idx);
>>>>    }
>>>>      /**
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>> index fe1a39f..1beb4e6 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>> @@ -31,6 +31,8 @@
>>>>    #include "amdgpu_ras.h"
>>>>    #include "amdgpu_xgmi.h"
>>>>    +#include <drm/drm_drv.h>
>>>> +
>>>>    /**
>>>>     * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>>>>     *
>>>> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>> void *cpu_pt_addr,
>>>>    {
>>>>        void __iomem *ptr = (void *)cpu_pt_addr;
>>>>        uint64_t value;
>>>> +    int idx;
>>>> +
>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>> +        return 0;
>>>>          /*
>>>>         * The following is for PTE only. GART does not have PDEs.
>>>> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>> void *cpu_pt_addr,
>>>>        value = addr & 0x0000FFFFFFFFF000ULL;
>>>>        value |= flags;
>>>>        writeq(value, ptr + (gpu_page_idx * 8));
>>>> +
>>>> +    drm_dev_exit(idx);
>>>> +
>>>>        return 0;
>>>>    }
>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>> index 523d22d..89e2bfe 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>> @@ -37,6 +37,8 @@
>>>>      #include "amdgpu_ras.h"
>>>>    +#include <drm/drm_drv.h>
>>>> +
>>>>    static int psp_sysfs_init(struct amdgpu_device *adev);
>>>>    static void psp_sysfs_fini(struct amdgpu_device *adev);
>>>>    @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>               struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>>>>    {
>>>>        int ret;
>>>> -    int index;
>>>> +    int index, idx;
>>>>        int timeout = 2000;
>>>>        bool ras_intr = false;
>>>>        bool skip_unsupport = false;
>>>> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>        if (psp->adev->in_pci_err_recovery)
>>>>            return 0;
>>>>    +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>> +        return 0;
>>>> +
>>>>        mutex_lock(&psp->mutex);
>>>>          memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
>>>> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>        ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr,
>>>> index);
>>>>        if (ret) {
>>>>            atomic_dec(&psp->fence_value);
>>>> -        mutex_unlock(&psp->mutex);
>>>> -        return ret;
>>>> +        goto exit;
>>>>        }
>>>>          amdgpu_asic_invalidate_hdp(psp->adev, NULL);
>>>> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>                 psp->cmd_buf_mem->cmd_id,
>>>>                 psp->cmd_buf_mem->resp.status);
>>>>            if (!timeout) {
>>>> -            mutex_unlock(&psp->mutex);
>>>> -            return -EINVAL;
>>>> +            ret = -EINVAL;
>>>> +            goto exit;
>>>>            }
>>>>        }
>>>>    @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>            ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>>>>            ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>>>>        }
>>>> -    mutex_unlock(&psp->mutex);
>>>>    +exit:
>>>> +    mutex_unlock(&psp->mutex);
>>>> +    drm_dev_exit(idx);
>>>>        return ret;
>>>>    }
>>>>    @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
>>>>        if (!cmd)
>>>>            return -ENOMEM;
>>>>        /* Copy toc to psp firmware private buffer */
>>>> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
>>>> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>>>>          psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size);
>>>>    @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
>>>>        if (!cmd)
>>>>            return -ENOMEM;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
>>>> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>>>>          psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>>>>                      psp->asd_ucode_size);
>>>> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>>>>        if (!cmd)
>>>>            return -ENOMEM;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>>>> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>                     psp->fw_pri_mc_addr,
>>>> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>>>>        if (!cmd)
>>>>            return -ENOMEM;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>>>> +    psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>                     psp->fw_pri_mc_addr,
>>>> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
>>>>        if (!cmd)
>>>>            return -ENOMEM;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
>>>> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>>>>               psp->ta_hdcp_ucode_size);
>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
>>>>        if (!cmd)
>>>>            return -ENOMEM;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>>>> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>                     psp->fw_pri_mc_addr,
>>>> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
>>>>        if (!cmd)
>>>>            return -ENOMEM;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>>>> +    psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>                     psp->fw_pri_mc_addr,
>>>> @@ -2778,6 +2777,20 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct
>>>> device *dev,
>>>>        return count;
>>>>    }
>>>>    +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>> bin_size)
>>>> +{
>>>> +    int idx;
>>>> +
>>>> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
>>>> +
>>>> +    drm_dev_exit(idx);
>>>> +}
>>>> +
>>>> +
>>>>    static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>>>>               psp_usbc_pd_fw_sysfs_read,
>>>>               psp_usbc_pd_fw_sysfs_write);
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>> index da250bc..ac69314 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
>>>>                  const char *chip_name);
>>>>    int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>>>>                        uint64_t *output_ptr);
>>>> +
>>>> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>> bin_size);
>>>> +
>>>>    #endif
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>> index 1a612f5..d656494 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>> @@ -35,6 +35,8 @@
>>>>    #include "amdgpu.h"
>>>>    #include "atom.h"
>>>>    +#include <drm/drm_drv.h>
>>>> +
>>>>    /*
>>>>     * Rings
>>>>     * Most engines on the GPU are fed via ring buffers.  Ring
>>>> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
>>>>        ring->sched.ready = !r;
>>>>        return r;
>>>>    }
>>>> +
>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>> +{
>>>> +    int idx;
>>>> +    int i = 0;
>>>> +
>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>> +    while (i <= ring->buf_mask)
>>>> +        ring->ring[i++] = ring->funcs->nop;
>>>> +
>>>> +    drm_dev_exit(idx);
>>>> +
>>>> +}
>>>> +
>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>> +{
>>>> +    int idx;
>>>> +
>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>> +    if (ring->count_dw <= 0)
>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>>>> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>> +    ring->wptr &= ring->ptr_mask;
>>>> +    ring->count_dw--;
>>>> +
>>>> +    drm_dev_exit(idx);
>>>> +}
>>>> +
>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>> +                          void *src, int count_dw)
>>>> +{
>>>> +    unsigned occupied, chunk1, chunk2;
>>>> +    void *dst;
>>>> +    int idx;
>>>> +
>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>> +        return;
>>>> +
>>>> +    if (unlikely(ring->count_dw < count_dw))
>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>>>> +
>>>> +    occupied = ring->wptr & ring->buf_mask;
>>>> +    dst = (void *)&ring->ring[occupied];
>>>> +    chunk1 = ring->buf_mask + 1 - occupied;
>>>> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>> +    chunk2 = count_dw - chunk1;
>>>> +    chunk1 <<= 2;
>>>> +    chunk2 <<= 2;
>>>> +
>>>> +    if (chunk1)
>>>> +        memcpy(dst, src, chunk1);
>>>> +
>>>> +    if (chunk2) {
>>>> +        src += chunk1;
>>>> +        dst = (void *)ring->ring;
>>>> +        memcpy(dst, src, chunk2);
>>>> +    }
>>>> +
>>>> +    ring->wptr += count_dw;
>>>> +    ring->wptr &= ring->ptr_mask;
>>>> +    ring->count_dw -= count_dw;
>>>> +
>>>> +    drm_dev_exit(idx);
>>>> +}
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>> index accb243..f90b81f 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>> @@ -300,53 +300,12 @@ static inline void
>>>> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>>>>        *ring->cond_exe_cpu_addr = cond_exec;
>>>>    }
>>>>    -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>> -{
>>>> -    int i = 0;
>>>> -    while (i <= ring->buf_mask)
>>>> -        ring->ring[i++] = ring->funcs->nop;
>>>> -
>>>> -}
>>>> -
>>>> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>> -{
>>>> -    if (ring->count_dw <= 0)
>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>>>> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>> -    ring->wptr &= ring->ptr_mask;
>>>> -    ring->count_dw--;
>>>> -}
>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>>>>    -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>> -                          void *src, int count_dw)
>>>> -{
>>>> -    unsigned occupied, chunk1, chunk2;
>>>> -    void *dst;
>>>> -
>>>> -    if (unlikely(ring->count_dw < count_dw))
>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
>>>> -
>>>> -    occupied = ring->wptr & ring->buf_mask;
>>>> -    dst = (void *)&ring->ring[occupied];
>>>> -    chunk1 = ring->buf_mask + 1 - occupied;
>>>> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>> -    chunk2 = count_dw - chunk1;
>>>> -    chunk1 <<= 2;
>>>> -    chunk2 <<= 2;
>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>>>>    -    if (chunk1)
>>>> -        memcpy(dst, src, chunk1);
>>>> -
>>>> -    if (chunk2) {
>>>> -        src += chunk1;
>>>> -        dst = (void *)ring->ring;
>>>> -        memcpy(dst, src, chunk2);
>>>> -    }
>>>> -
>>>> -    ring->wptr += count_dw;
>>>> -    ring->wptr &= ring->ptr_mask;
>>>> -    ring->count_dw -= count_dw;
>>>> -}
>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>> +                          void *src, int count_dw);
>>>>      int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>> index bd4248c..b3ce5be 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy PSP KDB binary to memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
>>>> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>          /* Provide the PSP KDB to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy PSP SPL binary to memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
>>>> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>>>>          /* Provide the PSP SPL to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>> @@ -335,10 +331,8 @@ static int psp_v11_0_bootloader_load_sysdrv(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy PSP System Driver binary to memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>          /* Provide the sys driver to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy Secure OS binary to PSP memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>          /* Provide the PSP secure OS to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>> index c4828bd..618e5b6 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>> @@ -138,10 +138,8 @@ static int psp_v12_0_bootloader_load_sysdrv(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy PSP System Driver binary to memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>          /* Provide the sys driver to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy Secure OS binary to PSP memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>          /* Provide the PSP secure OS to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>> index f2e725f..d0a6cccd 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>> @@ -102,10 +102,8 @@ static int psp_v3_1_bootloader_load_sysdrv(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy PSP System Driver binary to memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>          /* Provide the sys driver to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct
>>>> psp_context *psp)
>>>>        if (ret)
>>>>            return ret;
>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>> -
>>>>        /* Copy Secure OS binary to PSP memory */
>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>          /* Provide the PSP secure OS to bootloader */
>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>
>
Christian König Jan. 19, 2021, 6:59 p.m. UTC | #6
Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>
> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>> On Tue, Jan 19, 2021 at 4:35 PM Andrey Grodzovsky
>> <Andrey.Grodzovsky@amd.com> wrote:
>>> There is really no other way according to this article
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flwn.net%2FArticles%2F767885%2F&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7a1f5ae6a06f4661d47708d8bca4cb32%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466763278674162%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=QupsglO9WRuis8XRLBFIhl6miTXVOdAnk8oP4BfSclQ%3D&amp;reserved=0 
>>>
>>>
>>> "A perfect solution seems nearly impossible though; we cannot 
>>> acquire a mutex on
>>> the user
>>> to prevent them from yanking a device and we cannot check for a 
>>> presence change
>>> after every
>>> device access for performance reasons. "
>>>
>>> But I assumed srcu_read_lock should be pretty seamless performance 
>>> wise, no ?
>> The read side is supposed to be dirt cheap, the write side is were we
>> just stall for all readers to eventually complete on their own.
>> Definitely should be much cheaper than mmio read, on the mmio write
>> side it might actually hurt a bit. Otoh I think those don't stall the
>> cpu by default when they're timing out, so maybe if the overhead is
>> too much for those, we could omit them?
>>
>> Maybe just do a small microbenchmark for these for testing, with a
>> register that doesn't change hw state. So with and without
>> drm_dev_enter/exit, and also one with the hw plugged out so that we
>> have actual timeouts in the transactions.
>> -Daniel
>
>
> So say writing in a loop to some harmless scratch register for many 
> times both for plugged
> and unplugged case and measure total time delta ?

I think we should at least measure the following:

1. Writing X times to a scratch reg without your patch.
2. Writing X times to a scratch reg with your patch.
3. Writing X times to a scratch reg with the hardware physically 
disconnected.

I suggest to repeat that once for Polaris (or older) and once for Vega 
or Navi.

The SRBM on Polaris is meant to introduce some delay in each access, so 
it might react differently then the newer hardware.

Christian.

>
> Andrey
>
>
>>
>>> The other solution would be as I suggested to keep all the device IO 
>>> ranges
>>> reserved and system
>>> memory pages unfreed until the device is finalized in the driver but 
>>> Daniel said
>>> this would upset the PCI layer (the MMIO ranges reservation part).
>>>
>>> Andrey
>>>
>>>
>>>
>>>
>>> On 1/19/21 3:55 AM, Christian König wrote:
>>>> Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
>>>>> This should prevent writing to memory or IO ranges possibly
>>>>> already allocated for other uses after our device is removed.
>>>> Wow, that adds quite some overhead to every register access. I'm 
>>>> not sure we
>>>> can do this.
>>>>
>>>> Christian.
>>>>
>>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>>>>> ---
>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 
>>>>> ++++++++++++++++++++++++
>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 
>>>>> +++++++++++++---------
>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 
>>>>> ++++++++++++++++++++++++++++++
>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 
>>>>> ++-------------------
>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>>>>>    9 files changed, 184 insertions(+), 89 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>> index e99f4f1..0a9d73c 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>> @@ -72,6 +72,8 @@
>>>>>      #include <linux/iommu.h>
>>>>>    +#include <drm/drm_drv.h>
>>>>> +
>>>>>    MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>>>>>    MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>>>>>    MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
>>>>> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device 
>>>>> *adev,
>>>>> uint32_t offset)
>>>>>     */
>>>>>    void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t 
>>>>> offset, uint8_t
>>>>> value)
>>>>>    {
>>>>> +    int idx;
>>>>> +
>>>>>        if (adev->in_pci_err_recovery)
>>>>>            return;
>>>>>    +
>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>>        if (offset < adev->rmmio_size)
>>>>>            writeb(value, adev->rmmio + offset);
>>>>>        else
>>>>>            BUG();
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /**
>>>>> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device 
>>>>> *adev,
>>>>>                uint32_t reg, uint32_t v,
>>>>>                uint32_t acc_flags)
>>>>>    {
>>>>> +    int idx;
>>>>> +
>>>>>        if (adev->in_pci_err_recovery)
>>>>>            return;
>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>>        if ((reg * 4) < adev->rmmio_size) {
>>>>>            if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>>>>>                amdgpu_sriov_runtime(adev) &&
>>>>> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device 
>>>>> *adev,
>>>>>        }
>>>>> trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /*
>>>>> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device 
>>>>> *adev,
>>>>>    void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>>                     uint32_t reg, uint32_t v)
>>>>>    {
>>>>> +    int idx;
>>>>> +
>>>>>        if (adev->in_pci_err_recovery)
>>>>>            return;
>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>>        if (amdgpu_sriov_fullaccess(adev) &&
>>>>>            adev->gfx.rlc.funcs &&
>>>>> adev->gfx.rlc.funcs->is_rlcg_access_range) {
>>>>> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct 
>>>>> amdgpu_device *adev,
>>>>>        } else {
>>>>>            writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>>>>>        }
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /**
>>>>> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device 
>>>>> *adev, u32 reg)
>>>>>     */
>>>>>    void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>>>>>    {
>>>>> +    int idx;
>>>>> +
>>>>>        if (adev->in_pci_err_recovery)
>>>>>            return;
>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>>        if ((reg * 4) < adev->rio_mem_size)
>>>>>            iowrite32(v, adev->rio_mem + (reg * 4));
>>>>>        else {
>>>>>            iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>>>>>            iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>>>>>        }
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /**
>>>>> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device 
>>>>> *adev, u32
>>>>> index)
>>>>>     */
>>>>>    void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, 
>>>>> u32 v)
>>>>>    {
>>>>> +    int idx;
>>>>> +
>>>>>        if (adev->in_pci_err_recovery)
>>>>>            return;
>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>            writel(v, adev->doorbell.ptr + index);
>>>>>        } else {
>>>>>            DRM_ERROR("writing beyond doorbell aperture: 
>>>>> 0x%08x!\n", index);
>>>>>        }
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /**
>>>>> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct 
>>>>> amdgpu_device *adev,
>>>>> u32 index)
>>>>>     */
>>>>>    void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 
>>>>> index, u64 v)
>>>>>    {
>>>>> +    int idx;
>>>>> +
>>>>>        if (adev->in_pci_err_recovery)
>>>>>            return;
>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>            atomic64_set((atomic64_t *)(adev->doorbell.ptr + 
>>>>> index), v);
>>>>>        } else {
>>>>>            DRM_ERROR("writing beyond doorbell aperture: 
>>>>> 0x%08x!\n", index);
>>>>>        }
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /**
>>>>> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct 
>>>>> amdgpu_device
>>>>> *adev,
>>>>>        unsigned long flags;
>>>>>        void __iomem *pcie_index_offset;
>>>>>        void __iomem *pcie_data_offset;
>>>>> +    int idx;
>>>>> +
>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + 
>>>>> pcie_index * 4;
>>>>> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct 
>>>>> amdgpu_device *adev,
>>>>>        writel(reg_data, pcie_data_offset);
>>>>>        readl(pcie_data_offset);
>>>>>        spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /**
>>>>> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct 
>>>>> amdgpu_device
>>>>> *adev,
>>>>>        unsigned long flags;
>>>>>        void __iomem *pcie_index_offset;
>>>>>        void __iomem *pcie_data_offset;
>>>>> +    int idx;
>>>>> +
>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return;
>>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + 
>>>>> pcie_index * 4;
>>>>> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct 
>>>>> amdgpu_device
>>>>> *adev,
>>>>>        writel((u32)(reg_data >> 32), pcie_data_offset);
>>>>>        readl(pcie_data_offset);
>>>>>        spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>>    }
>>>>>      /**
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>> index fe1a39f..1beb4e6 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>> @@ -31,6 +31,8 @@
>>>>>    #include "amdgpu_ras.h"
>>>>>    #include "amdgpu_xgmi.h"
>>>>>    +#include <drm/drm_drv.h>
>>>>> +
>>>>>    /**
>>>>>     * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>>>>>     *
>>>>> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct 
>>>>> amdgpu_device *adev,
>>>>> void *cpu_pt_addr,
>>>>>    {
>>>>>        void __iomem *ptr = (void *)cpu_pt_addr;
>>>>>        uint64_t value;
>>>>> +    int idx;
>>>>> +
>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>> +        return 0;
>>>>>          /*
>>>>>         * The following is for PTE only. GART does not have PDEs.
>>>>> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct 
>>>>> amdgpu_device *adev,
>>>>> void *cpu_pt_addr,
>>>>>        value = addr & 0x0000FFFFFFFFF000ULL;
>>>>>        value |= flags;
>>>>>        writeq(value, ptr + (gpu_page_idx * 8));
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>> +
>>>>>        return 0;
>>>>>    }
>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>> index 523d22d..89e2bfe 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>> @@ -37,6 +37,8 @@
>>>>>      #include "amdgpu_ras.h"
>>>>>    +#include <drm/drm_drv.h>
>>>>> +
>>>>>    static int psp_sysfs_init(struct amdgpu_device *adev);
>>>>>    static void psp_sysfs_fini(struct amdgpu_device *adev);
>>>>>    @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>               struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>>>>>    {
>>>>>        int ret;
>>>>> -    int index;
>>>>> +    int index, idx;
>>>>>        int timeout = 2000;
>>>>>        bool ras_intr = false;
>>>>>        bool skip_unsupport = false;
>>>>> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>        if (psp->adev->in_pci_err_recovery)
>>>>>            return 0;
>>>>>    +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>> +        return 0;
>>>>> +
>>>>>        mutex_lock(&psp->mutex);
>>>>>          memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
>>>>> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>        ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, 
>>>>> fence_mc_addr,
>>>>> index);
>>>>>        if (ret) {
>>>>>            atomic_dec(&psp->fence_value);
>>>>> -        mutex_unlock(&psp->mutex);
>>>>> -        return ret;
>>>>> +        goto exit;
>>>>>        }
>>>>>          amdgpu_asic_invalidate_hdp(psp->adev, NULL);
>>>>> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>                 psp->cmd_buf_mem->cmd_id,
>>>>>                 psp->cmd_buf_mem->resp.status);
>>>>>            if (!timeout) {
>>>>> -            mutex_unlock(&psp->mutex);
>>>>> -            return -EINVAL;
>>>>> +            ret = -EINVAL;
>>>>> +            goto exit;
>>>>>            }
>>>>>        }
>>>>>    @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>            ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>>>>>            ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>>>>>        }
>>>>> -    mutex_unlock(&psp->mutex);
>>>>>    +exit:
>>>>> +    mutex_unlock(&psp->mutex);
>>>>> +    drm_dev_exit(idx);
>>>>>        return ret;
>>>>>    }
>>>>>    @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context 
>>>>> *psp,
>>>>>        if (!cmd)
>>>>>            return -ENOMEM;
>>>>>        /* Copy toc to psp firmware private buffer */
>>>>> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
>>>>> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>>>>>          psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, 
>>>>> psp->toc_bin_size);
>>>>>    @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context 
>>>>> *psp)
>>>>>        if (!cmd)
>>>>>            return -ENOMEM;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, 
>>>>> psp->asd_ucode_size);
>>>>> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>>>>>          psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>>>>>                      psp->asd_ucode_size);
>>>>> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>>>>>        if (!cmd)
>>>>>            return -ENOMEM;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, 
>>>>> psp->ta_xgmi_ucode_size);
>>>>> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, 
>>>>> psp->ta_xgmi_ucode_size);
>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>                     psp->fw_pri_mc_addr,
>>>>> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>>>>>        if (!cmd)
>>>>>            return -ENOMEM;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, 
>>>>> psp->ta_ras_ucode_size);
>>>>> +    psp_copy_fw(psp, psp->ta_ras_start_addr, 
>>>>> psp->ta_ras_ucode_size);
>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>                     psp->fw_pri_mc_addr,
>>>>> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context 
>>>>> *psp)
>>>>>        if (!cmd)
>>>>>            return -ENOMEM;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
>>>>> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>>>>>               psp->ta_hdcp_ucode_size);
>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context 
>>>>> *psp)
>>>>>        if (!cmd)
>>>>>            return -ENOMEM;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, 
>>>>> psp->ta_dtm_ucode_size);
>>>>> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, 
>>>>> psp->ta_dtm_ucode_size);
>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>                     psp->fw_pri_mc_addr,
>>>>> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context 
>>>>> *psp)
>>>>>        if (!cmd)
>>>>>            return -ENOMEM;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, 
>>>>> psp->ta_rap_ucode_size);
>>>>> +    psp_copy_fw(psp, psp->ta_rap_start_addr, 
>>>>> psp->ta_rap_ucode_size);
>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>                     psp->fw_pri_mc_addr,
>>>>> @@ -2778,6 +2777,20 @@ static ssize_t 
>>>>> psp_usbc_pd_fw_sysfs_write(struct
>>>>> device *dev,
>>>>>        return count;
>>>>>    }
>>>>>    +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, 
>>>>> uint32_t
>>>>> bin_size)
>>>>> +{
>>>>> +    int idx;
>>>>> +
>>>>> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>> +}
>>>>> +
>>>>> +
>>>>>    static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>>>>>               psp_usbc_pd_fw_sysfs_read,
>>>>>               psp_usbc_pd_fw_sysfs_write);
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>> index da250bc..ac69314 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context 
>>>>> *psp,
>>>>>                  const char *chip_name);
>>>>>    int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>>>>>                        uint64_t *output_ptr);
>>>>> +
>>>>> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, 
>>>>> uint32_t
>>>>> bin_size);
>>>>> +
>>>>>    #endif
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>> index 1a612f5..d656494 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>> @@ -35,6 +35,8 @@
>>>>>    #include "amdgpu.h"
>>>>>    #include "atom.h"
>>>>>    +#include <drm/drm_drv.h>
>>>>> +
>>>>>    /*
>>>>>     * Rings
>>>>>     * Most engines on the GPU are fed via ring buffers. Ring
>>>>> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct 
>>>>> amdgpu_ring *ring)
>>>>>        ring->sched.ready = !r;
>>>>>        return r;
>>>>>    }
>>>>> +
>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>>> +{
>>>>> +    int idx;
>>>>> +    int i = 0;
>>>>> +
>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>> +    while (i <= ring->buf_mask)
>>>>> +        ring->ring[i++] = ring->funcs->nop;
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>> +
>>>>> +}
>>>>> +
>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>>> +{
>>>>> +    int idx;
>>>>> +
>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>> +    if (ring->count_dw <= 0)
>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>> expected!\n");
>>>>> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>> +    ring->count_dw--;
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>> +}
>>>>> +
>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>> +                          void *src, int count_dw)
>>>>> +{
>>>>> +    unsigned occupied, chunk1, chunk2;
>>>>> +    void *dst;
>>>>> +    int idx;
>>>>> +
>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>> +        return;
>>>>> +
>>>>> +    if (unlikely(ring->count_dw < count_dw))
>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>> expected!\n");
>>>>> +
>>>>> +    occupied = ring->wptr & ring->buf_mask;
>>>>> +    dst = (void *)&ring->ring[occupied];
>>>>> +    chunk1 = ring->buf_mask + 1 - occupied;
>>>>> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>> +    chunk2 = count_dw - chunk1;
>>>>> +    chunk1 <<= 2;
>>>>> +    chunk2 <<= 2;
>>>>> +
>>>>> +    if (chunk1)
>>>>> +        memcpy(dst, src, chunk1);
>>>>> +
>>>>> +    if (chunk2) {
>>>>> +        src += chunk1;
>>>>> +        dst = (void *)ring->ring;
>>>>> +        memcpy(dst, src, chunk2);
>>>>> +    }
>>>>> +
>>>>> +    ring->wptr += count_dw;
>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>> +    ring->count_dw -= count_dw;
>>>>> +
>>>>> +    drm_dev_exit(idx);
>>>>> +}
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>> index accb243..f90b81f 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>> @@ -300,53 +300,12 @@ static inline void
>>>>> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>>>>>        *ring->cond_exe_cpu_addr = cond_exec;
>>>>>    }
>>>>>    -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring 
>>>>> *ring)
>>>>> -{
>>>>> -    int i = 0;
>>>>> -    while (i <= ring->buf_mask)
>>>>> -        ring->ring[i++] = ring->funcs->nop;
>>>>> -
>>>>> -}
>>>>> -
>>>>> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, 
>>>>> uint32_t v)
>>>>> -{
>>>>> -    if (ring->count_dw <= 0)
>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>> expected!\n");
>>>>> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>> -    ring->count_dw--;
>>>>> -}
>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>>>>>    -static inline void amdgpu_ring_write_multiple(struct 
>>>>> amdgpu_ring *ring,
>>>>> -                          void *src, int count_dw)
>>>>> -{
>>>>> -    unsigned occupied, chunk1, chunk2;
>>>>> -    void *dst;
>>>>> -
>>>>> -    if (unlikely(ring->count_dw < count_dw))
>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>> expected!\n");
>>>>> -
>>>>> -    occupied = ring->wptr & ring->buf_mask;
>>>>> -    dst = (void *)&ring->ring[occupied];
>>>>> -    chunk1 = ring->buf_mask + 1 - occupied;
>>>>> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>> -    chunk2 = count_dw - chunk1;
>>>>> -    chunk1 <<= 2;
>>>>> -    chunk2 <<= 2;
>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>>>>>    -    if (chunk1)
>>>>> -        memcpy(dst, src, chunk1);
>>>>> -
>>>>> -    if (chunk2) {
>>>>> -        src += chunk1;
>>>>> -        dst = (void *)ring->ring;
>>>>> -        memcpy(dst, src, chunk2);
>>>>> -    }
>>>>> -
>>>>> -    ring->wptr += count_dw;
>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>> -    ring->count_dw -= count_dw;
>>>>> -}
>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>> +                          void *src, int count_dw);
>>>>>      int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>> index bd4248c..b3ce5be 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy PSP KDB binary to memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>>          /* Provide the PSP KDB to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy PSP SPL binary to memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
>>>>> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>>>>>          /* Provide the PSP SPL to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>> @@ -335,10 +331,8 @@ static int 
>>>>> psp_v11_0_bootloader_load_sysdrv(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy PSP System Driver binary to memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>          /* Provide the sys driver to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>> index c4828bd..618e5b6 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>> @@ -138,10 +138,8 @@ static int 
>>>>> psp_v12_0_bootloader_load_sysdrv(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy PSP System Driver binary to memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>          /* Provide the sys driver to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>> index f2e725f..d0a6cccd 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>> @@ -102,10 +102,8 @@ static int 
>>>>> psp_v3_1_bootloader_load_sysdrv(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy PSP System Driver binary to memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>          /* Provide the sys driver to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct
>>>>> psp_context *psp)
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>> -
>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>
>>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Andrey Grodzovsky Jan. 19, 2021, 7:16 p.m. UTC | #7
On 1/19/21 1:59 PM, Christian König wrote:
> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>
>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>> On Tue, Jan 19, 2021 at 4:35 PM Andrey Grodzovsky
>>> <Andrey.Grodzovsky@amd.com> wrote:
>>>> There is really no other way according to this article
>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flwn.net%2FArticles%2F767885%2F&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cee61fb937d2d4baedf6f08d8bcac5b02%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466795752297305%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=a9Y4ZMEVYaMP7IeMVxQgXGpAkDXSkedMAiWkyqwzEe8%3D&amp;reserved=0 
>>>>
>>>>
>>>> "A perfect solution seems nearly impossible though; we cannot acquire a 
>>>> mutex on
>>>> the user
>>>> to prevent them from yanking a device and we cannot check for a presence 
>>>> change
>>>> after every
>>>> device access for performance reasons. "
>>>>
>>>> But I assumed srcu_read_lock should be pretty seamless performance wise, no ?
>>> The read side is supposed to be dirt cheap, the write side is were we
>>> just stall for all readers to eventually complete on their own.
>>> Definitely should be much cheaper than mmio read, on the mmio write
>>> side it might actually hurt a bit. Otoh I think those don't stall the
>>> cpu by default when they're timing out, so maybe if the overhead is
>>> too much for those, we could omit them?
>>>
>>> Maybe just do a small microbenchmark for these for testing, with a
>>> register that doesn't change hw state. So with and without
>>> drm_dev_enter/exit, and also one with the hw plugged out so that we
>>> have actual timeouts in the transactions.
>>> -Daniel
>>
>>
>> So say writing in a loop to some harmless scratch register for many times 
>> both for plugged
>> and unplugged case and measure total time delta ?
>
> I think we should at least measure the following:
>
> 1. Writing X times to a scratch reg without your patch.
> 2. Writing X times to a scratch reg with your patch.
> 3. Writing X times to a scratch reg with the hardware physically disconnected.
>
> I suggest to repeat that once for Polaris (or older) and once for Vega or Navi.
>
> The SRBM on Polaris is meant to introduce some delay in each access, so it 
> might react differently then the newer hardware.
>
> Christian.


Will do.

Andrey


>
>>
>> Andrey
>>
>>
>>>
>>>> The other solution would be as I suggested to keep all the device IO ranges
>>>> reserved and system
>>>> memory pages unfreed until the device is finalized in the driver but Daniel 
>>>> said
>>>> this would upset the PCI layer (the MMIO ranges reservation part).
>>>>
>>>> Andrey
>>>>
>>>>
>>>>
>>>>
>>>> On 1/19/21 3:55 AM, Christian König wrote:
>>>>> Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
>>>>>> This should prevent writing to memory or IO ranges possibly
>>>>>> already allocated for other uses after our device is removed.
>>>>> Wow, that adds quite some overhead to every register access. I'm not sure we
>>>>> can do this.
>>>>>
>>>>> Christian.
>>>>>
>>>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>>>>>> ---
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 
>>>>>> ++++++++++++++++++++++++++++++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>>>>>>    9 files changed, 184 insertions(+), 89 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> index e99f4f1..0a9d73c 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> @@ -72,6 +72,8 @@
>>>>>>      #include <linux/iommu.h>
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>>>>>>    MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>>>>>>    MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
>>>>>> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev,
>>>>>> uint32_t offset)
>>>>>>     */
>>>>>>    void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t
>>>>>> value)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (offset < adev->rmmio_size)
>>>>>>            writeb(value, adev->rmmio + offset);
>>>>>>        else
>>>>>>            BUG();
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>                uint32_t reg, uint32_t v,
>>>>>>                uint32_t acc_flags)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if ((reg * 4) < adev->rmmio_size) {
>>>>>>            if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>>>>>>                amdgpu_sriov_runtime(adev) &&
>>>>>> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>        }
>>>>>> trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /*
>>>>>> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>    void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>>>                     uint32_t reg, uint32_t v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (amdgpu_sriov_fullaccess(adev) &&
>>>>>>            adev->gfx.rlc.funcs &&
>>>>>> adev->gfx.rlc.funcs->is_rlcg_access_range) {
>>>>>> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>>>        } else {
>>>>>>            writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 
>>>>>> reg)
>>>>>>     */
>>>>>>    void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if ((reg * 4) < adev->rio_mem_size)
>>>>>>            iowrite32(v, adev->rio_mem + (reg * 4));
>>>>>>        else {
>>>>>>            iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>>>>>>            iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, 
>>>>>> u32
>>>>>> index)
>>>>>>     */
>>>>>>    void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>>            writel(v, adev->doorbell.ptr + index);
>>>>>>        } else {
>>>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev,
>>>>>> u32 index)
>>>>>>     */
>>>>>>    void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>>            atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
>>>>>>        } else {
>>>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device
>>>>>> *adev,
>>>>>>        unsigned long flags;
>>>>>>        void __iomem *pcie_index_offset;
>>>>>>        void __iomem *pcie_data_offset;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>>>> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device 
>>>>>> *adev,
>>>>>>        writel(reg_data, pcie_data_offset);
>>>>>>        readl(pcie_data_offset);
>>>>>> spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
>>>>>> *adev,
>>>>>>        unsigned long flags;
>>>>>>        void __iomem *pcie_index_offset;
>>>>>>        void __iomem *pcie_data_offset;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>>>> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
>>>>>> *adev,
>>>>>>        writel((u32)(reg_data >> 32), pcie_data_offset);
>>>>>>        readl(pcie_data_offset);
>>>>>> spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> index fe1a39f..1beb4e6 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> @@ -31,6 +31,8 @@
>>>>>>    #include "amdgpu_ras.h"
>>>>>>    #include "amdgpu_xgmi.h"
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    /**
>>>>>>     * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>>>>>>     *
>>>>>> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>>>> void *cpu_pt_addr,
>>>>>>    {
>>>>>>        void __iomem *ptr = (void *)cpu_pt_addr;
>>>>>>        uint64_t value;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return 0;
>>>>>>          /*
>>>>>>         * The following is for PTE only. GART does not have PDEs.
>>>>>> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>>>> void *cpu_pt_addr,
>>>>>>        value = addr & 0x0000FFFFFFFFF000ULL;
>>>>>>        value |= flags;
>>>>>>        writeq(value, ptr + (gpu_page_idx * 8));
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +
>>>>>>        return 0;
>>>>>>    }
>>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> index 523d22d..89e2bfe 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> @@ -37,6 +37,8 @@
>>>>>>      #include "amdgpu_ras.h"
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    static int psp_sysfs_init(struct amdgpu_device *adev);
>>>>>>    static void psp_sysfs_fini(struct amdgpu_device *adev);
>>>>>>    @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>               struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>>>>>>    {
>>>>>>        int ret;
>>>>>> -    int index;
>>>>>> +    int index, idx;
>>>>>>        int timeout = 2000;
>>>>>>        bool ras_intr = false;
>>>>>>        bool skip_unsupport = false;
>>>>>> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>        if (psp->adev->in_pci_err_recovery)
>>>>>>            return 0;
>>>>>>    +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>>> +        return 0;
>>>>>> +
>>>>>>        mutex_lock(&psp->mutex);
>>>>>>          memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
>>>>>> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>        ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr,
>>>>>> index);
>>>>>>        if (ret) {
>>>>>>            atomic_dec(&psp->fence_value);
>>>>>> -        mutex_unlock(&psp->mutex);
>>>>>> -        return ret;
>>>>>> +        goto exit;
>>>>>>        }
>>>>>>          amdgpu_asic_invalidate_hdp(psp->adev, NULL);
>>>>>> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>                 psp->cmd_buf_mem->cmd_id,
>>>>>>                 psp->cmd_buf_mem->resp.status);
>>>>>>            if (!timeout) {
>>>>>> -            mutex_unlock(&psp->mutex);
>>>>>> -            return -EINVAL;
>>>>>> +            ret = -EINVAL;
>>>>>> +            goto exit;
>>>>>>            }
>>>>>>        }
>>>>>>    @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>            ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>>>>>>            ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>>>>>>        }
>>>>>> -    mutex_unlock(&psp->mutex);
>>>>>>    +exit:
>>>>>> +    mutex_unlock(&psp->mutex);
>>>>>> +    drm_dev_exit(idx);
>>>>>>        return ret;
>>>>>>    }
>>>>>>    @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>        /* Copy toc to psp firmware private buffer */
>>>>>> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>>>>>>          psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, 
>>>>>> psp->toc_bin_size);
>>>>>>    @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>>>>>>          psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>>>>>>                      psp->asd_ucode_size);
>>>>>> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, 
>>>>>> psp->ta_xgmi_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, 
>>>>>> psp->ta_ras_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
>>>>>> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>>>>>>               psp->ta_hdcp_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, 
>>>>>> psp->ta_dtm_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, 
>>>>>> psp->ta_rap_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -2778,6 +2777,20 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct
>>>>>> device *dev,
>>>>>>        return count;
>>>>>>    }
>>>>>>    +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>>>> bin_size)
>>>>>> +{
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +}
>>>>>> +
>>>>>> +
>>>>>>    static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>>>>>>               psp_usbc_pd_fw_sysfs_read,
>>>>>>               psp_usbc_pd_fw_sysfs_write);
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> index da250bc..ac69314 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
>>>>>>                  const char *chip_name);
>>>>>>    int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>>>>>>                        uint64_t *output_ptr);
>>>>>> +
>>>>>> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>>>> bin_size);
>>>>>> +
>>>>>>    #endif
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> index 1a612f5..d656494 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> @@ -35,6 +35,8 @@
>>>>>>    #include "amdgpu.h"
>>>>>>    #include "atom.h"
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    /*
>>>>>>     * Rings
>>>>>>     * Most engines on the GPU are fed via ring buffers. Ring
>>>>>> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
>>>>>>        ring->sched.ready = !r;
>>>>>>        return r;
>>>>>>    }
>>>>>> +
>>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>>>> +{
>>>>>> +    int idx;
>>>>>> +    int i = 0;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    while (i <= ring->buf_mask)
>>>>>> +        ring->ring[i++] = ring->funcs->nop;
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +
>>>>>> +}
>>>>>> +
>>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>>>> +{
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    if (ring->count_dw <= 0)
>>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>>> +    ring->count_dw--;
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +}
>>>>>> +
>>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>> +                          void *src, int count_dw)
>>>>>> +{
>>>>>> +    unsigned occupied, chunk1, chunk2;
>>>>>> +    void *dst;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    if (unlikely(ring->count_dw < count_dw))
>>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> +
>>>>>> +    occupied = ring->wptr & ring->buf_mask;
>>>>>> +    dst = (void *)&ring->ring[occupied];
>>>>>> +    chunk1 = ring->buf_mask + 1 - occupied;
>>>>>> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>>> +    chunk2 = count_dw - chunk1;
>>>>>> +    chunk1 <<= 2;
>>>>>> +    chunk2 <<= 2;
>>>>>> +
>>>>>> +    if (chunk1)
>>>>>> +        memcpy(dst, src, chunk1);
>>>>>> +
>>>>>> +    if (chunk2) {
>>>>>> +        src += chunk1;
>>>>>> +        dst = (void *)ring->ring;
>>>>>> +        memcpy(dst, src, chunk2);
>>>>>> +    }
>>>>>> +
>>>>>> +    ring->wptr += count_dw;
>>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>>> +    ring->count_dw -= count_dw;
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +}
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> index accb243..f90b81f 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> @@ -300,53 +300,12 @@ static inline void
>>>>>> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>>>>>>        *ring->cond_exe_cpu_addr = cond_exec;
>>>>>>    }
>>>>>>    -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>>>> -{
>>>>>> -    int i = 0;
>>>>>> -    while (i <= ring->buf_mask)
>>>>>> -        ring->ring[i++] = ring->funcs->nop;
>>>>>> -
>>>>>> -}
>>>>>> -
>>>>>> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>>>> -{
>>>>>> -    if (ring->count_dw <= 0)
>>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>>> -    ring->count_dw--;
>>>>>> -}
>>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>>>>>>    -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>> -                          void *src, int count_dw)
>>>>>> -{
>>>>>> -    unsigned occupied, chunk1, chunk2;
>>>>>> -    void *dst;
>>>>>> -
>>>>>> -    if (unlikely(ring->count_dw < count_dw))
>>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> -
>>>>>> -    occupied = ring->wptr & ring->buf_mask;
>>>>>> -    dst = (void *)&ring->ring[occupied];
>>>>>> -    chunk1 = ring->buf_mask + 1 - occupied;
>>>>>> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>>> -    chunk2 = count_dw - chunk1;
>>>>>> -    chunk1 <<= 2;
>>>>>> -    chunk2 <<= 2;
>>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>>>>>>    -    if (chunk1)
>>>>>> -        memcpy(dst, src, chunk1);
>>>>>> -
>>>>>> -    if (chunk2) {
>>>>>> -        src += chunk1;
>>>>>> -        dst = (void *)ring->ring;
>>>>>> -        memcpy(dst, src, chunk2);
>>>>>> -    }
>>>>>> -
>>>>>> -    ring->wptr += count_dw;
>>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>>> -    ring->count_dw -= count_dw;
>>>>>> -}
>>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>> +                          void *src, int count_dw);
>>>>>>      int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> index bd4248c..b3ce5be 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP KDB binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>>>          /* Provide the PSP KDB to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP SPL binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>>>>>>          /* Provide the PSP SPL to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -335,10 +331,8 @@ static int psp_v11_0_bootloader_load_sysdrv(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> index c4828bd..618e5b6 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> @@ -138,10 +138,8 @@ static int psp_v12_0_bootloader_load_sysdrv(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> index f2e725f..d0a6cccd 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> @@ -102,10 +102,8 @@ static int psp_v3_1_bootloader_load_sysdrv(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>
>>>
>> _______________________________________________
>> amd-gfx mailing list
>> amd-gfx@lists.freedesktop.org
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cee61fb937d2d4baedf6f08d8bcac5b02%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466795752297305%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=a5MkPkwHh7WkR24K9EoCWSKPdCpiXCJH6RwGbGyhHyA%3D&amp;reserved=0 
>>
>
Andrey Grodzovsky Jan. 20, 2021, 7:34 p.m. UTC | #8
On 1/19/21 2:16 PM, Andrey Grodzovsky wrote:
>
> On 1/19/21 1:59 PM, Christian König wrote:
>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>>
>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>>> On Tue, Jan 19, 2021 at 4:35 PM Andrey Grodzovsky
>>>> <Andrey.Grodzovsky@amd.com> wrote:
>>>>> There is really no other way according to this article
>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flwn.net%2FArticles%2F767885%2F&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cee61fb937d2d4baedf6f08d8bcac5b02%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466795752297305%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=a9Y4ZMEVYaMP7IeMVxQgXGpAkDXSkedMAiWkyqwzEe8%3D&amp;reserved=0 
>>>>>
>>>>>
>>>>> "A perfect solution seems nearly impossible though; we cannot acquire a 
>>>>> mutex on
>>>>> the user
>>>>> to prevent them from yanking a device and we cannot check for a presence 
>>>>> change
>>>>> after every
>>>>> device access for performance reasons. "
>>>>>
>>>>> But I assumed srcu_read_lock should be pretty seamless performance wise, no ?
>>>> The read side is supposed to be dirt cheap, the write side is were we
>>>> just stall for all readers to eventually complete on their own.
>>>> Definitely should be much cheaper than mmio read, on the mmio write
>>>> side it might actually hurt a bit. Otoh I think those don't stall the
>>>> cpu by default when they're timing out, so maybe if the overhead is
>>>> too much for those, we could omit them?
>>>>
>>>> Maybe just do a small microbenchmark for these for testing, with a
>>>> register that doesn't change hw state. So with and without
>>>> drm_dev_enter/exit, and also one with the hw plugged out so that we
>>>> have actual timeouts in the transactions.
>>>> -Daniel
>>>
>>>
>>> So say writing in a loop to some harmless scratch register for many times 
>>> both for plugged
>>> and unplugged case and measure total time delta ?
>>
>> I think we should at least measure the following:
>>
>> 1. Writing X times to a scratch reg without your patch.
>> 2. Writing X times to a scratch reg with your patch.
>> 3. Writing X times to a scratch reg with the hardware physically disconnected.


Just realized, I can't test this part since I don't have eGPU to yank out.

Andrey


>>
>> I suggest to repeat that once for Polaris (or older) and once for Vega or Navi.
>>
>> The SRBM on Polaris is meant to introduce some delay in each access, so it 
>> might react differently then the newer hardware.
>>
>> Christian.
>
>
> Will do.
>
> Andrey
>
>
>>
>>>
>>> Andrey
>>>
>>>
>>>>
>>>>> The other solution would be as I suggested to keep all the device IO ranges
>>>>> reserved and system
>>>>> memory pages unfreed until the device is finalized in the driver but 
>>>>> Daniel said
>>>>> this would upset the PCI layer (the MMIO ranges reservation part).
>>>>>
>>>>> Andrey
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On 1/19/21 3:55 AM, Christian König wrote:
>>>>>> Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
>>>>>>> This should prevent writing to memory or IO ranges possibly
>>>>>>> already allocated for other uses after our device is removed.
>>>>>> Wow, that adds quite some overhead to every register access. I'm not sure we
>>>>>> can do this.
>>>>>>
>>>>>> Christian.
>>>>>>
>>>>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>>>>>>> ---
>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 
>>>>>>> ++++++++++++++++++++++++++++++
>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
>>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>>>>>>>    9 files changed, 184 insertions(+), 89 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>> index e99f4f1..0a9d73c 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>> @@ -72,6 +72,8 @@
>>>>>>>      #include <linux/iommu.h>
>>>>>>>    +#include <drm/drm_drv.h>
>>>>>>> +
>>>>>>>    MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>>>>>>>    MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>>>>>>>    MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
>>>>>>> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev,
>>>>>>> uint32_t offset)
>>>>>>>     */
>>>>>>>    void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, 
>>>>>>> uint8_t
>>>>>>> value)
>>>>>>>    {
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>>            return;
>>>>>>>    +
>>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>>        if (offset < adev->rmmio_size)
>>>>>>>            writeb(value, adev->rmmio + offset);
>>>>>>>        else
>>>>>>>            BUG();
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /**
>>>>>>> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>>                uint32_t reg, uint32_t v,
>>>>>>>                uint32_t acc_flags)
>>>>>>>    {
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>>            return;
>>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>>        if ((reg * 4) < adev->rmmio_size) {
>>>>>>>            if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>>>>>>>                amdgpu_sriov_runtime(adev) &&
>>>>>>> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>>        }
>>>>>>> trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /*
>>>>>>> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>>    void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>>>>                     uint32_t reg, uint32_t v)
>>>>>>>    {
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>>            return;
>>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>>        if (amdgpu_sriov_fullaccess(adev) &&
>>>>>>>            adev->gfx.rlc.funcs &&
>>>>>>> adev->gfx.rlc.funcs->is_rlcg_access_range) {
>>>>>>> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device 
>>>>>>> *adev,
>>>>>>>        } else {
>>>>>>>            writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>>>>>>>        }
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /**
>>>>>>> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 
>>>>>>> reg)
>>>>>>>     */
>>>>>>>    void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>>>>>>>    {
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>>            return;
>>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>>        if ((reg * 4) < adev->rio_mem_size)
>>>>>>>            iowrite32(v, adev->rio_mem + (reg * 4));
>>>>>>>        else {
>>>>>>>            iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>>>>>>>            iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>>>>>>>        }
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /**
>>>>>>> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device 
>>>>>>> *adev, u32
>>>>>>> index)
>>>>>>>     */
>>>>>>>    void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
>>>>>>>    {
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>>            return;
>>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>>>            writel(v, adev->doorbell.ptr + index);
>>>>>>>        } else {
>>>>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>>>>        }
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /**
>>>>>>> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev,
>>>>>>> u32 index)
>>>>>>>     */
>>>>>>>    void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
>>>>>>>    {
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>>            return;
>>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>>>            atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
>>>>>>>        } else {
>>>>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>>>>        }
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /**
>>>>>>> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device
>>>>>>> *adev,
>>>>>>>        unsigned long flags;
>>>>>>>        void __iomem *pcie_index_offset;
>>>>>>>        void __iomem *pcie_data_offset;
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>>>>> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct 
>>>>>>> amdgpu_device *adev,
>>>>>>>        writel(reg_data, pcie_data_offset);
>>>>>>>        readl(pcie_data_offset);
>>>>>>> spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /**
>>>>>>> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct 
>>>>>>> amdgpu_device
>>>>>>> *adev,
>>>>>>>        unsigned long flags;
>>>>>>>        void __iomem *pcie_index_offset;
>>>>>>>        void __iomem *pcie_data_offset;
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>>>>> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
>>>>>>> *adev,
>>>>>>>        writel((u32)(reg_data >> 32), pcie_data_offset);
>>>>>>>        readl(pcie_data_offset);
>>>>>>> spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>    }
>>>>>>>      /**
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>>> index fe1a39f..1beb4e6 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>>> @@ -31,6 +31,8 @@
>>>>>>>    #include "amdgpu_ras.h"
>>>>>>>    #include "amdgpu_xgmi.h"
>>>>>>>    +#include <drm/drm_drv.h>
>>>>>>> +
>>>>>>>    /**
>>>>>>>     * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>>>>>>>     *
>>>>>>> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>>>>> void *cpu_pt_addr,
>>>>>>>    {
>>>>>>>        void __iomem *ptr = (void *)cpu_pt_addr;
>>>>>>>        uint64_t value;
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>>> +        return 0;
>>>>>>>          /*
>>>>>>>         * The following is for PTE only. GART does not have PDEs.
>>>>>>> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>>>>> void *cpu_pt_addr,
>>>>>>>        value = addr & 0x0000FFFFFFFFF000ULL;
>>>>>>>        value |= flags;
>>>>>>>        writeq(value, ptr + (gpu_page_idx * 8));
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>> +
>>>>>>>        return 0;
>>>>>>>    }
>>>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>>> index 523d22d..89e2bfe 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>>> @@ -37,6 +37,8 @@
>>>>>>>      #include "amdgpu_ras.h"
>>>>>>>    +#include <drm/drm_drv.h>
>>>>>>> +
>>>>>>>    static int psp_sysfs_init(struct amdgpu_device *adev);
>>>>>>>    static void psp_sysfs_fini(struct amdgpu_device *adev);
>>>>>>>    @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>>               struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>>>>>>>    {
>>>>>>>        int ret;
>>>>>>> -    int index;
>>>>>>> +    int index, idx;
>>>>>>>        int timeout = 2000;
>>>>>>>        bool ras_intr = false;
>>>>>>>        bool skip_unsupport = false;
>>>>>>> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>>        if (psp->adev->in_pci_err_recovery)
>>>>>>>            return 0;
>>>>>>>    +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>>>> +        return 0;
>>>>>>> +
>>>>>>>        mutex_lock(&psp->mutex);
>>>>>>>          memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
>>>>>>> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>>        ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr,
>>>>>>> index);
>>>>>>>        if (ret) {
>>>>>>>            atomic_dec(&psp->fence_value);
>>>>>>> -        mutex_unlock(&psp->mutex);
>>>>>>> -        return ret;
>>>>>>> +        goto exit;
>>>>>>>        }
>>>>>>>          amdgpu_asic_invalidate_hdp(psp->adev, NULL);
>>>>>>> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>>                 psp->cmd_buf_mem->cmd_id,
>>>>>>>                 psp->cmd_buf_mem->resp.status);
>>>>>>>            if (!timeout) {
>>>>>>> -            mutex_unlock(&psp->mutex);
>>>>>>> -            return -EINVAL;
>>>>>>> +            ret = -EINVAL;
>>>>>>> +            goto exit;
>>>>>>>            }
>>>>>>>        }
>>>>>>>    @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>>            ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>>>>>>>            ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>>>>>>>        }
>>>>>>> -    mutex_unlock(&psp->mutex);
>>>>>>>    +exit:
>>>>>>> +    mutex_unlock(&psp->mutex);
>>>>>>> +    drm_dev_exit(idx);
>>>>>>>        return ret;
>>>>>>>    }
>>>>>>>    @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
>>>>>>>        if (!cmd)
>>>>>>>            return -ENOMEM;
>>>>>>>        /* Copy toc to psp firmware private buffer */
>>>>>>> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>>>>>>>          psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, 
>>>>>>> psp->toc_bin_size);
>>>>>>>    @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
>>>>>>>        if (!cmd)
>>>>>>>            return -ENOMEM;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
>>>>>>> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>>>>>>>          psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>>>>>>>                      psp->asd_ucode_size);
>>>>>>> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>>>>>>>        if (!cmd)
>>>>>>>            return -ENOMEM;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, 
>>>>>>> psp->ta_xgmi_ucode_size);
>>>>>>> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>>                     psp->fw_pri_mc_addr,
>>>>>>> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>>>>>>>        if (!cmd)
>>>>>>>            return -ENOMEM;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, 
>>>>>>> psp->ta_ras_ucode_size);
>>>>>>> +    psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>>                     psp->fw_pri_mc_addr,
>>>>>>> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
>>>>>>>        if (!cmd)
>>>>>>>            return -ENOMEM;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
>>>>>>> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>>>>>>>               psp->ta_hdcp_ucode_size);
>>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
>>>>>>>        if (!cmd)
>>>>>>>            return -ENOMEM;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, 
>>>>>>> psp->ta_dtm_ucode_size);
>>>>>>> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>>                     psp->fw_pri_mc_addr,
>>>>>>> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
>>>>>>>        if (!cmd)
>>>>>>>            return -ENOMEM;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, 
>>>>>>> psp->ta_rap_ucode_size);
>>>>>>> +    psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>>                     psp->fw_pri_mc_addr,
>>>>>>> @@ -2778,6 +2777,20 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct
>>>>>>> device *dev,
>>>>>>>        return count;
>>>>>>>    }
>>>>>>>    +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>>>>> bin_size)
>>>>>>> +{
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>> +}
>>>>>>> +
>>>>>>> +
>>>>>>>    static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>>>>>>>               psp_usbc_pd_fw_sysfs_read,
>>>>>>>               psp_usbc_pd_fw_sysfs_write);
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>>> index da250bc..ac69314 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>>> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
>>>>>>>                  const char *chip_name);
>>>>>>>    int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>>>>>>>                        uint64_t *output_ptr);
>>>>>>> +
>>>>>>> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>>>>> bin_size);
>>>>>>> +
>>>>>>>    #endif
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>>> index 1a612f5..d656494 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>>> @@ -35,6 +35,8 @@
>>>>>>>    #include "amdgpu.h"
>>>>>>>    #include "atom.h"
>>>>>>>    +#include <drm/drm_drv.h>
>>>>>>> +
>>>>>>>    /*
>>>>>>>     * Rings
>>>>>>>     * Most engines on the GPU are fed via ring buffers. Ring
>>>>>>> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
>>>>>>>        ring->sched.ready = !r;
>>>>>>>        return r;
>>>>>>>    }
>>>>>>> +
>>>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>>>>> +{
>>>>>>> +    int idx;
>>>>>>> +    int i = 0;
>>>>>>> +
>>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>> +    while (i <= ring->buf_mask)
>>>>>>> +        ring->ring[i++] = ring->funcs->nop;
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>> +
>>>>>>> +}
>>>>>>> +
>>>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>>>>> +{
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>> +    if (ring->count_dw <= 0)
>>>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>>> expected!\n");
>>>>>>> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>>>> +    ring->count_dw--;
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>> +}
>>>>>>> +
>>>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>>> +                          void *src, int count_dw)
>>>>>>> +{
>>>>>>> +    unsigned occupied, chunk1, chunk2;
>>>>>>> +    void *dst;
>>>>>>> +    int idx;
>>>>>>> +
>>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>>> +        return;
>>>>>>> +
>>>>>>> +    if (unlikely(ring->count_dw < count_dw))
>>>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>>> expected!\n");
>>>>>>> +
>>>>>>> +    occupied = ring->wptr & ring->buf_mask;
>>>>>>> +    dst = (void *)&ring->ring[occupied];
>>>>>>> +    chunk1 = ring->buf_mask + 1 - occupied;
>>>>>>> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>>>> +    chunk2 = count_dw - chunk1;
>>>>>>> +    chunk1 <<= 2;
>>>>>>> +    chunk2 <<= 2;
>>>>>>> +
>>>>>>> +    if (chunk1)
>>>>>>> +        memcpy(dst, src, chunk1);
>>>>>>> +
>>>>>>> +    if (chunk2) {
>>>>>>> +        src += chunk1;
>>>>>>> +        dst = (void *)ring->ring;
>>>>>>> +        memcpy(dst, src, chunk2);
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    ring->wptr += count_dw;
>>>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>>>> +    ring->count_dw -= count_dw;
>>>>>>> +
>>>>>>> +    drm_dev_exit(idx);
>>>>>>> +}
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>>> index accb243..f90b81f 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>>> @@ -300,53 +300,12 @@ static inline void
>>>>>>> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>>>>>>>        *ring->cond_exe_cpu_addr = cond_exec;
>>>>>>>    }
>>>>>>>    -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>>>>> -{
>>>>>>> -    int i = 0;
>>>>>>> -    while (i <= ring->buf_mask)
>>>>>>> -        ring->ring[i++] = ring->funcs->nop;
>>>>>>> -
>>>>>>> -}
>>>>>>> -
>>>>>>> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>>>>> -{
>>>>>>> -    if (ring->count_dw <= 0)
>>>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>>> expected!\n");
>>>>>>> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>>>> -    ring->count_dw--;
>>>>>>> -}
>>>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>>>>>>>    -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>>> -                          void *src, int count_dw)
>>>>>>> -{
>>>>>>> -    unsigned occupied, chunk1, chunk2;
>>>>>>> -    void *dst;
>>>>>>> -
>>>>>>> -    if (unlikely(ring->count_dw < count_dw))
>>>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>>> expected!\n");
>>>>>>> -
>>>>>>> -    occupied = ring->wptr & ring->buf_mask;
>>>>>>> -    dst = (void *)&ring->ring[occupied];
>>>>>>> -    chunk1 = ring->buf_mask + 1 - occupied;
>>>>>>> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>>>> -    chunk2 = count_dw - chunk1;
>>>>>>> -    chunk1 <<= 2;
>>>>>>> -    chunk2 <<= 2;
>>>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>>>>>>>    -    if (chunk1)
>>>>>>> -        memcpy(dst, src, chunk1);
>>>>>>> -
>>>>>>> -    if (chunk2) {
>>>>>>> -        src += chunk1;
>>>>>>> -        dst = (void *)ring->ring;
>>>>>>> -        memcpy(dst, src, chunk2);
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    ring->wptr += count_dw;
>>>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>>>> -    ring->count_dw -= count_dw;
>>>>>>> -}
>>>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>>> +                          void *src, int count_dw);
>>>>>>>      int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>>>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>>> index bd4248c..b3ce5be 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>>> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy PSP KDB binary to memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>>>>          /* Provide the PSP KDB to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>>> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy PSP SPL binary to memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>>>>>>>          /* Provide the PSP SPL to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>>> @@ -335,10 +331,8 @@ static int psp_v11_0_bootloader_load_sysdrv(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>>> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>>> index c4828bd..618e5b6 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>>> @@ -138,10 +138,8 @@ static int psp_v12_0_bootloader_load_sysdrv(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>>> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>>> index f2e725f..d0a6cccd 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>>> @@ -102,10 +102,8 @@ static int psp_v3_1_bootloader_load_sysdrv(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>>> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct
>>>>>>> psp_context *psp)
>>>>>>>        if (ret)
>>>>>>>            return ret;
>>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>>> -
>>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>
>>>>
>>> _______________________________________________
>>> amd-gfx mailing list
>>> amd-gfx@lists.freedesktop.org
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cee61fb937d2d4baedf6f08d8bcac5b02%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466795752297305%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=a5MkPkwHh7WkR24K9EoCWSKPdCpiXCJH6RwGbGyhHyA%3D&amp;reserved=0 
>>>
>>
Andrey Grodzovsky Jan. 28, 2021, 5:23 p.m. UTC | #9
On 1/19/21 1:59 PM, Christian König wrote:
> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>
>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>> On Tue, Jan 19, 2021 at 4:35 PM Andrey Grodzovsky
>>> <Andrey.Grodzovsky@amd.com> wrote:
>>>> There is really no other way according to this article
>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flwn.net%2FArticles%2F767885%2F&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cee61fb937d2d4baedf6f08d8bcac5b02%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466795752297305%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=a9Y4ZMEVYaMP7IeMVxQgXGpAkDXSkedMAiWkyqwzEe8%3D&amp;reserved=0 
>>>>
>>>>
>>>> "A perfect solution seems nearly impossible though; we cannot acquire a 
>>>> mutex on
>>>> the user
>>>> to prevent them from yanking a device and we cannot check for a presence 
>>>> change
>>>> after every
>>>> device access for performance reasons. "
>>>>
>>>> But I assumed srcu_read_lock should be pretty seamless performance wise, no ?
>>> The read side is supposed to be dirt cheap, the write side is were we
>>> just stall for all readers to eventually complete on their own.
>>> Definitely should be much cheaper than mmio read, on the mmio write
>>> side it might actually hurt a bit. Otoh I think those don't stall the
>>> cpu by default when they're timing out, so maybe if the overhead is
>>> too much for those, we could omit them?
>>>
>>> Maybe just do a small microbenchmark for these for testing, with a
>>> register that doesn't change hw state. So with and without
>>> drm_dev_enter/exit, and also one with the hw plugged out so that we
>>> have actual timeouts in the transactions.
>>> -Daniel
>>
>>
>> So say writing in a loop to some harmless scratch register for many times 
>> both for plugged
>> and unplugged case and measure total time delta ?
>
> I think we should at least measure the following:
>
> 1. Writing X times to a scratch reg without your patch.
> 2. Writing X times to a scratch reg with your patch.
> 3. Writing X times to a scratch reg with the hardware physically disconnected.
>
> I suggest to repeat that once for Polaris (or older) and once for Vega or Navi.
>
> The SRBM on Polaris is meant to introduce some delay in each access, so it 
> might react differently then the newer hardware.
>
> Christian.


See attached results and the testing code. Ran on Polaris (gfx8) and Vega10(gfx9)

In summary, over 1 million WWREG32 in loop with and without this patch you get 
around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for each 
WWREG32) for using drm_dev_enter check when writing registers.

P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.

diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c 
b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 3763921..1650549 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -873,6 +873,11 @@ static int gfx_v8_0_ring_test_ring(struct amdgpu_ring *ring)
         if (i >= adev->usec_timeout)
                 r = -ETIMEDOUT;

+       DRM_ERROR("Before write 1M times to scratch register");
+       for (i = 0; i < 1000000; i++)
+               WREG32(scratch, 0xDEADBEEF);
+       DRM_ERROR("After write 1M times to scratch register");
+
  error_free_scratch:
         amdgpu_gfx_scratch_free(adev, scratch);
         return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c 
b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 5f4805e..7ecbfef 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -1063,6 +1063,11 @@ static int gfx_v9_0_ring_test_ring(struct amdgpu_ring *ring)
         if (i >= adev->usec_timeout)
                 r = -ETIMEDOUT;

+       DRM_ERROR("Before write 1M times to scratch register");
+       for (i = 0; i < 1000000; i++)
+               WREG32(scratch, 0xDEADBEEF);
+       DRM_ERROR("After write 1M times to scratch register");
+
  error_free_scratch:
         amdgpu_gfx_scratch_free(adev, scratch);
         return r;


Andrey


Andrey



>
>>
>> Andrey
>>
>>
>>>
>>>> The other solution would be as I suggested to keep all the device IO ranges
>>>> reserved and system
>>>> memory pages unfreed until the device is finalized in the driver but Daniel 
>>>> said
>>>> this would upset the PCI layer (the MMIO ranges reservation part).
>>>>
>>>> Andrey
>>>>
>>>>
>>>>
>>>>
>>>> On 1/19/21 3:55 AM, Christian König wrote:
>>>>> Am 18.01.21 um 22:01 schrieb Andrey Grodzovsky:
>>>>>> This should prevent writing to memory or IO ranges possibly
>>>>>> already allocated for other uses after our device is removed.
>>>>> Wow, that adds quite some overhead to every register access. I'm not sure we
>>>>> can do this.
>>>>>
>>>>> Christian.
>>>>>
>>>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>>>>>> ---
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 57 ++++++++++++++++++++++++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c    |  9 ++++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c    | 53 +++++++++++++---------
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h    |  3 ++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c   | 70 
>>>>>> ++++++++++++++++++++++++++++++
>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h   | 49 ++-------------------
>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v11_0.c     | 16 ++-----
>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v12_0.c     |  8 +---
>>>>>>    drivers/gpu/drm/amd/amdgpu/psp_v3_1.c      |  8 +---
>>>>>>    9 files changed, 184 insertions(+), 89 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> index e99f4f1..0a9d73c 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> @@ -72,6 +72,8 @@
>>>>>>      #include <linux/iommu.h>
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
>>>>>>    MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
>>>>>>    MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
>>>>>> @@ -404,13 +406,21 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev,
>>>>>> uint32_t offset)
>>>>>>     */
>>>>>>    void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t
>>>>>> value)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (offset < adev->rmmio_size)
>>>>>>            writeb(value, adev->rmmio + offset);
>>>>>>        else
>>>>>>            BUG();
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -427,9 +437,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>                uint32_t reg, uint32_t v,
>>>>>>                uint32_t acc_flags)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if ((reg * 4) < adev->rmmio_size) {
>>>>>>            if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
>>>>>>                amdgpu_sriov_runtime(adev) &&
>>>>>> @@ -444,6 +459,8 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>        }
>>>>>> trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /*
>>>>>> @@ -454,9 +471,14 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
>>>>>>    void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>>>                     uint32_t reg, uint32_t v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (amdgpu_sriov_fullaccess(adev) &&
>>>>>>            adev->gfx.rlc.funcs &&
>>>>>> adev->gfx.rlc.funcs->is_rlcg_access_range) {
>>>>>> @@ -465,6 +487,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
>>>>>>        } else {
>>>>>>            writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -499,15 +523,22 @@ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 
>>>>>> reg)
>>>>>>     */
>>>>>>    void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if ((reg * 4) < adev->rio_mem_size)
>>>>>>            iowrite32(v, adev->rio_mem + (reg * 4));
>>>>>>        else {
>>>>>>            iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
>>>>>>            iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -544,14 +575,21 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, 
>>>>>> u32
>>>>>> index)
>>>>>>     */
>>>>>>    void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>>            writel(v, adev->doorbell.ptr + index);
>>>>>>        } else {
>>>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -588,14 +626,21 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev,
>>>>>> u32 index)
>>>>>>     */
>>>>>>    void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
>>>>>>    {
>>>>>> +    int idx;
>>>>>> +
>>>>>>        if (adev->in_pci_err_recovery)
>>>>>>            return;
>>>>>>    +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>>        if (index < adev->doorbell.num_doorbells) {
>>>>>>            atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
>>>>>>        } else {
>>>>>>            DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
>>>>>>        }
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -682,6 +727,10 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device
>>>>>> *adev,
>>>>>>        unsigned long flags;
>>>>>>        void __iomem *pcie_index_offset;
>>>>>>        void __iomem *pcie_data_offset;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>>>> @@ -692,6 +741,8 @@ void amdgpu_device_indirect_wreg(struct amdgpu_device 
>>>>>> *adev,
>>>>>>        writel(reg_data, pcie_data_offset);
>>>>>>        readl(pcie_data_offset);
>>>>>> spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> @@ -711,6 +762,10 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
>>>>>> *adev,
>>>>>>        unsigned long flags;
>>>>>>        void __iomem *pcie_index_offset;
>>>>>>        void __iomem *pcie_data_offset;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return;
>>>>>>          spin_lock_irqsave(&adev->pcie_idx_lock, flags);
>>>>>>        pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
>>>>>> @@ -727,6 +782,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device
>>>>>> *adev,
>>>>>>        writel((u32)(reg_data >> 32), pcie_data_offset);
>>>>>>        readl(pcie_data_offset);
>>>>>> spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>>    }
>>>>>>      /**
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> index fe1a39f..1beb4e6 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
>>>>>> @@ -31,6 +31,8 @@
>>>>>>    #include "amdgpu_ras.h"
>>>>>>    #include "amdgpu_xgmi.h"
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    /**
>>>>>>     * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
>>>>>>     *
>>>>>> @@ -98,6 +100,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>>>> void *cpu_pt_addr,
>>>>>>    {
>>>>>>        void __iomem *ptr = (void *)cpu_pt_addr;
>>>>>>        uint64_t value;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&adev->ddev, &idx))
>>>>>> +        return 0;
>>>>>>          /*
>>>>>>         * The following is for PTE only. GART does not have PDEs.
>>>>>> @@ -105,6 +111,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev,
>>>>>> void *cpu_pt_addr,
>>>>>>        value = addr & 0x0000FFFFFFFFF000ULL;
>>>>>>        value |= flags;
>>>>>>        writeq(value, ptr + (gpu_page_idx * 8));
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +
>>>>>>        return 0;
>>>>>>    }
>>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> index 523d22d..89e2bfe 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
>>>>>> @@ -37,6 +37,8 @@
>>>>>>      #include "amdgpu_ras.h"
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    static int psp_sysfs_init(struct amdgpu_device *adev);
>>>>>>    static void psp_sysfs_fini(struct amdgpu_device *adev);
>>>>>>    @@ -248,7 +250,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>               struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
>>>>>>    {
>>>>>>        int ret;
>>>>>> -    int index;
>>>>>> +    int index, idx;
>>>>>>        int timeout = 2000;
>>>>>>        bool ras_intr = false;
>>>>>>        bool skip_unsupport = false;
>>>>>> @@ -256,6 +258,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>        if (psp->adev->in_pci_err_recovery)
>>>>>>            return 0;
>>>>>>    +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>>> +        return 0;
>>>>>> +
>>>>>>        mutex_lock(&psp->mutex);
>>>>>>          memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
>>>>>> @@ -266,8 +271,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>        ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr,
>>>>>> index);
>>>>>>        if (ret) {
>>>>>>            atomic_dec(&psp->fence_value);
>>>>>> -        mutex_unlock(&psp->mutex);
>>>>>> -        return ret;
>>>>>> +        goto exit;
>>>>>>        }
>>>>>>          amdgpu_asic_invalidate_hdp(psp->adev, NULL);
>>>>>> @@ -307,8 +311,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>                 psp->cmd_buf_mem->cmd_id,
>>>>>>                 psp->cmd_buf_mem->resp.status);
>>>>>>            if (!timeout) {
>>>>>> -            mutex_unlock(&psp->mutex);
>>>>>> -            return -EINVAL;
>>>>>> +            ret = -EINVAL;
>>>>>> +            goto exit;
>>>>>>            }
>>>>>>        }
>>>>>>    @@ -316,8 +320,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
>>>>>>            ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
>>>>>>            ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
>>>>>>        }
>>>>>> -    mutex_unlock(&psp->mutex);
>>>>>>    +exit:
>>>>>> +    mutex_unlock(&psp->mutex);
>>>>>> +    drm_dev_exit(idx);
>>>>>>        return ret;
>>>>>>    }
>>>>>>    @@ -354,8 +360,7 @@ static int psp_load_toc(struct psp_context *psp,
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>        /* Copy toc to psp firmware private buffer */
>>>>>> -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
>>>>>>          psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, 
>>>>>> psp->toc_bin_size);
>>>>>>    @@ -570,8 +575,7 @@ static int psp_asd_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
>>>>>>          psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
>>>>>>                      psp->asd_ucode_size);
>>>>>> @@ -726,8 +730,7 @@ static int psp_xgmi_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, 
>>>>>> psp->ta_xgmi_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -982,8 +985,7 @@ static int psp_ras_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, 
>>>>>> psp->ta_ras_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -1219,8 +1221,7 @@ static int psp_hdcp_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
>>>>>> +    psp_copy_fw(psp, psp->ta_hdcp_start_addr,
>>>>>>               psp->ta_hdcp_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>> @@ -1366,8 +1367,7 @@ static int psp_dtm_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, 
>>>>>> psp->ta_dtm_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -1507,8 +1507,7 @@ static int psp_rap_load(struct psp_context *psp)
>>>>>>        if (!cmd)
>>>>>>            return -ENOMEM;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -    memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, 
>>>>>> psp->ta_rap_ucode_size);
>>>>>> +    psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
>>>>>>          psp_prep_ta_load_cmd_buf(cmd,
>>>>>>                     psp->fw_pri_mc_addr,
>>>>>> @@ -2778,6 +2777,20 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct
>>>>>> device *dev,
>>>>>>        return count;
>>>>>>    }
>>>>>>    +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>>>> bin_size)
>>>>>> +{
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&psp->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> +    memcpy(psp->fw_pri_buf, start_addr, bin_size);
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +}
>>>>>> +
>>>>>> +
>>>>>>    static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
>>>>>>               psp_usbc_pd_fw_sysfs_read,
>>>>>>               psp_usbc_pd_fw_sysfs_write);
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> index da250bc..ac69314 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
>>>>>> @@ -400,4 +400,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
>>>>>>                  const char *chip_name);
>>>>>>    int psp_get_fw_attestation_records_addr(struct psp_context *psp,
>>>>>>                        uint64_t *output_ptr);
>>>>>> +
>>>>>> +void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t
>>>>>> bin_size);
>>>>>> +
>>>>>>    #endif
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> index 1a612f5..d656494 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>>>>> @@ -35,6 +35,8 @@
>>>>>>    #include "amdgpu.h"
>>>>>>    #include "atom.h"
>>>>>>    +#include <drm/drm_drv.h>
>>>>>> +
>>>>>>    /*
>>>>>>     * Rings
>>>>>>     * Most engines on the GPU are fed via ring buffers. Ring
>>>>>> @@ -463,3 +465,71 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
>>>>>>        ring->sched.ready = !r;
>>>>>>        return r;
>>>>>>    }
>>>>>> +
>>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>>>> +{
>>>>>> +    int idx;
>>>>>> +    int i = 0;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    while (i <= ring->buf_mask)
>>>>>> +        ring->ring[i++] = ring->funcs->nop;
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +
>>>>>> +}
>>>>>> +
>>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>>>> +{
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    if (ring->count_dw <= 0)
>>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> +    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>>> +    ring->count_dw--;
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +}
>>>>>> +
>>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>> +                          void *src, int count_dw)
>>>>>> +{
>>>>>> +    unsigned occupied, chunk1, chunk2;
>>>>>> +    void *dst;
>>>>>> +    int idx;
>>>>>> +
>>>>>> +    if (!drm_dev_enter(&ring->adev->ddev, &idx))
>>>>>> +        return;
>>>>>> +
>>>>>> +    if (unlikely(ring->count_dw < count_dw))
>>>>>> +        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> +
>>>>>> +    occupied = ring->wptr & ring->buf_mask;
>>>>>> +    dst = (void *)&ring->ring[occupied];
>>>>>> +    chunk1 = ring->buf_mask + 1 - occupied;
>>>>>> +    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>>> +    chunk2 = count_dw - chunk1;
>>>>>> +    chunk1 <<= 2;
>>>>>> +    chunk2 <<= 2;
>>>>>> +
>>>>>> +    if (chunk1)
>>>>>> +        memcpy(dst, src, chunk1);
>>>>>> +
>>>>>> +    if (chunk2) {
>>>>>> +        src += chunk1;
>>>>>> +        dst = (void *)ring->ring;
>>>>>> +        memcpy(dst, src, chunk2);
>>>>>> +    }
>>>>>> +
>>>>>> +    ring->wptr += count_dw;
>>>>>> +    ring->wptr &= ring->ptr_mask;
>>>>>> +    ring->count_dw -= count_dw;
>>>>>> +
>>>>>> +    drm_dev_exit(idx);
>>>>>> +}
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> index accb243..f90b81f 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>>>>> @@ -300,53 +300,12 @@ static inline void
>>>>>> amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
>>>>>>        *ring->cond_exe_cpu_addr = cond_exec;
>>>>>>    }
>>>>>>    -static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
>>>>>> -{
>>>>>> -    int i = 0;
>>>>>> -    while (i <= ring->buf_mask)
>>>>>> -        ring->ring[i++] = ring->funcs->nop;
>>>>>> -
>>>>>> -}
>>>>>> -
>>>>>> -static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
>>>>>> -{
>>>>>> -    if (ring->count_dw <= 0)
>>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> -    ring->ring[ring->wptr++ & ring->buf_mask] = v;
>>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>>> -    ring->count_dw--;
>>>>>> -}
>>>>>> +void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
>>>>>>    -static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>> -                          void *src, int count_dw)
>>>>>> -{
>>>>>> -    unsigned occupied, chunk1, chunk2;
>>>>>> -    void *dst;
>>>>>> -
>>>>>> -    if (unlikely(ring->count_dw < count_dw))
>>>>>> -        DRM_ERROR("amdgpu: writing more dwords to the ring than 
>>>>>> expected!\n");
>>>>>> -
>>>>>> -    occupied = ring->wptr & ring->buf_mask;
>>>>>> -    dst = (void *)&ring->ring[occupied];
>>>>>> -    chunk1 = ring->buf_mask + 1 - occupied;
>>>>>> -    chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
>>>>>> -    chunk2 = count_dw - chunk1;
>>>>>> -    chunk1 <<= 2;
>>>>>> -    chunk2 <<= 2;
>>>>>> +void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
>>>>>>    -    if (chunk1)
>>>>>> -        memcpy(dst, src, chunk1);
>>>>>> -
>>>>>> -    if (chunk2) {
>>>>>> -        src += chunk1;
>>>>>> -        dst = (void *)ring->ring;
>>>>>> -        memcpy(dst, src, chunk2);
>>>>>> -    }
>>>>>> -
>>>>>> -    ring->wptr += count_dw;
>>>>>> -    ring->wptr &= ring->ptr_mask;
>>>>>> -    ring->count_dw -= count_dw;
>>>>>> -}
>>>>>> +void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
>>>>>> +                          void *src, int count_dw);
>>>>>>      int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
>>>>>>    diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> index bd4248c..b3ce5be 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>>>>> @@ -269,10 +269,8 @@ static int psp_v11_0_bootloader_load_kdb(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP KDB binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
>>>>>>          /* Provide the PSP KDB to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -302,10 +300,8 @@ static int psp_v11_0_bootloader_load_spl(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP SPL binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
>>>>>>          /* Provide the PSP SPL to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -335,10 +331,8 @@ static int psp_v11_0_bootloader_load_sysdrv(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -371,10 +365,8 @@ static int psp_v11_0_bootloader_load_sos(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> index c4828bd..618e5b6 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
>>>>>> @@ -138,10 +138,8 @@ static int psp_v12_0_bootloader_load_sysdrv(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -179,10 +177,8 @@ static int psp_v12_0_bootloader_load_sos(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> index f2e725f..d0a6cccd 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
>>>>>> @@ -102,10 +102,8 @@ static int psp_v3_1_bootloader_load_sysdrv(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy PSP System Driver binary to memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
>>>>>>          /* Provide the sys driver to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>>>> @@ -143,10 +141,8 @@ static int psp_v3_1_bootloader_load_sos(struct
>>>>>> psp_context *psp)
>>>>>>        if (ret)
>>>>>>            return ret;
>>>>>>    -    memset(psp->fw_pri_buf, 0, PSP_1_MEG);
>>>>>> -
>>>>>>        /* Copy Secure OS binary to PSP memory */
>>>>>> -    memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
>>>>>> +    psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
>>>>>>          /* Provide the PSP secure OS to bootloader */
>>>>>>        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
>>>
>>>
>> _______________________________________________
>> amd-gfx mailing list
>> amd-gfx@lists.freedesktop.org
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cee61fb937d2d4baedf6f08d8bcac5b02%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637466795752297305%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=a5MkPkwHh7WkR24K9EoCWSKPdCpiXCJH6RwGbGyhHyA%3D&amp;reserved=0 
>>
>
Christian König Jan. 29, 2021, 3:16 p.m. UTC | #10
Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
>
> On 1/19/21 1:59 PM, Christian König wrote:
>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>>
>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>>> [SNIP]
>>> So say writing in a loop to some harmless scratch register for many 
>>> times both for plugged
>>> and unplugged case and measure total time delta ?
>>
>> I think we should at least measure the following:
>>
>> 1. Writing X times to a scratch reg without your patch.
>> 2. Writing X times to a scratch reg with your patch.
>> 3. Writing X times to a scratch reg with the hardware physically 
>> disconnected.
>>
>> I suggest to repeat that once for Polaris (or older) and once for 
>> Vega or Navi.
>>
>> The SRBM on Polaris is meant to introduce some delay in each access, 
>> so it might react differently then the newer hardware.
>>
>> Christian.
>
>
> See attached results and the testing code. Ran on Polaris (gfx8) and 
> Vega10(gfx9)
>
> In summary, over 1 million WWREG32 in loop with and without this patch 
> you get around 10ms of accumulated overhead ( so 0.00001 millisecond 
> penalty for each WWREG32) for using drm_dev_enter check when writing 
> registers.
>
> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.

Well if I'm not completely mistaken that are 100ms of accumulated 
overhead. So around 100ns per write. And even bigger problem is that 
this is a ~67% increase.

I'm not sure how many write we do during normal operation, but that 
sounds like a bit much. Ideas?

Christian.
Andrey Grodzovsky Jan. 29, 2021, 5:35 p.m. UTC | #11
On 1/29/21 10:16 AM, Christian König wrote:
> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
>>
>> On 1/19/21 1:59 PM, Christian König wrote:
>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>>>
>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>>>> [SNIP]
>>>> So say writing in a loop to some harmless scratch register for many times 
>>>> both for plugged
>>>> and unplugged case and measure total time delta ?
>>>
>>> I think we should at least measure the following:
>>>
>>> 1. Writing X times to a scratch reg without your patch.
>>> 2. Writing X times to a scratch reg with your patch.
>>> 3. Writing X times to a scratch reg with the hardware physically disconnected.
>>>
>>> I suggest to repeat that once for Polaris (or older) and once for Vega or Navi.
>>>
>>> The SRBM on Polaris is meant to introduce some delay in each access, so it 
>>> might react differently then the newer hardware.
>>>
>>> Christian.
>>
>>
>> See attached results and the testing code. Ran on Polaris (gfx8) and 
>> Vega10(gfx9)
>>
>> In summary, over 1 million WWREG32 in loop with and without this patch you 
>> get around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for 
>> each WWREG32) for using drm_dev_enter check when writing registers.
>>
>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.
>
> Well if I'm not completely mistaken that are 100ms of accumulated overhead. So 
> around 100ns per write. And even bigger problem is that this is a ~67% increase.


My bad, and 67% from what ? How u calculate ?


>
> I'm not sure how many write we do during normal operation, but that sounds 
> like a bit much. Ideas?


Well, u suggested to move the drm_dev_enter way up but as i see it the problem 
with this is that it increase the chance of race where the
device is extracted after we check for drm_dev_enter (there is also such chance 
even when it's placed inside WWREG but it's lower).
Earlier I propsed that instead of doing all those guards scattered all over the 
code simply delay release of system memory pages and unreserve of
MMIO ranges to until after the device itself is gone after last drm device 
reference is dropped. But Daniel opposes delaying MMIO ranges unreserve to after
PCI remove code because according to him it will upset the PCI subsytem.

Andrey

>
> Christian.
Christian König Jan. 29, 2021, 7:25 p.m. UTC | #12
Am 29.01.21 um 18:35 schrieb Andrey Grodzovsky:
>
> On 1/29/21 10:16 AM, Christian König wrote:
>> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
>>>
>>> On 1/19/21 1:59 PM, Christian König wrote:
>>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>>>>
>>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>>>>> [SNIP]
>>>>> So say writing in a loop to some harmless scratch register for 
>>>>> many times both for plugged
>>>>> and unplugged case and measure total time delta ?
>>>>
>>>> I think we should at least measure the following:
>>>>
>>>> 1. Writing X times to a scratch reg without your patch.
>>>> 2. Writing X times to a scratch reg with your patch.
>>>> 3. Writing X times to a scratch reg with the hardware physically 
>>>> disconnected.
>>>>
>>>> I suggest to repeat that once for Polaris (or older) and once for 
>>>> Vega or Navi.
>>>>
>>>> The SRBM on Polaris is meant to introduce some delay in each 
>>>> access, so it might react differently then the newer hardware.
>>>>
>>>> Christian.
>>>
>>>
>>> See attached results and the testing code. Ran on Polaris (gfx8) and 
>>> Vega10(gfx9)
>>>
>>> In summary, over 1 million WWREG32 in loop with and without this 
>>> patch you get around 10ms of accumulated overhead ( so 0.00001 
>>> millisecond penalty for each WWREG32) for using drm_dev_enter check 
>>> when writing registers.
>>>
>>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have 
>>> one.
>>
>> Well if I'm not completely mistaken that are 100ms of accumulated 
>> overhead. So around 100ns per write. And even bigger problem is that 
>> this is a ~67% increase.
>
>
> My bad, and 67% from what ? How u calculate ?

My bad, (308501-209689)/209689=47% increase.

>>
>> I'm not sure how many write we do during normal operation, but that 
>> sounds like a bit much. Ideas?
>
> Well, u suggested to move the drm_dev_enter way up but as i see it the 
> problem with this is that it increase the chance of race where the
> device is extracted after we check for drm_dev_enter (there is also 
> such chance even when it's placed inside WWREG but it's lower).
> Earlier I propsed that instead of doing all those guards scattered all 
> over the code simply delay release of system memory pages and 
> unreserve of
> MMIO ranges to until after the device itself is gone after last drm 
> device reference is dropped. But Daniel opposes delaying MMIO ranges 
> unreserve to after
> PCI remove code because according to him it will upset the PCI subsytem.

Yeah, that's most likely true as well.

Maybe Daniel has another idea when he's back from vacation.

Christian.

>
> Andrey
>
>>
>> Christian.
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Andrey Grodzovsky Feb. 5, 2021, 4:22 p.m. UTC | #13
Daniel, ping. Also, please refer to the other thread with Bjorn from pci-dev
on the same topic I added you to.

Andrey

On 1/29/21 2:25 PM, Christian König wrote:
> Am 29.01.21 um 18:35 schrieb Andrey Grodzovsky:
>>
>> On 1/29/21 10:16 AM, Christian König wrote:
>>> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
>>>>
>>>> On 1/19/21 1:59 PM, Christian König wrote:
>>>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>>>>>
>>>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>>>>>> [SNIP]
>>>>>> So say writing in a loop to some harmless scratch register for many times 
>>>>>> both for plugged
>>>>>> and unplugged case and measure total time delta ?
>>>>>
>>>>> I think we should at least measure the following:
>>>>>
>>>>> 1. Writing X times to a scratch reg without your patch.
>>>>> 2. Writing X times to a scratch reg with your patch.
>>>>> 3. Writing X times to a scratch reg with the hardware physically disconnected.
>>>>>
>>>>> I suggest to repeat that once for Polaris (or older) and once for Vega or 
>>>>> Navi.
>>>>>
>>>>> The SRBM on Polaris is meant to introduce some delay in each access, so it 
>>>>> might react differently then the newer hardware.
>>>>>
>>>>> Christian.
>>>>
>>>>
>>>> See attached results and the testing code. Ran on Polaris (gfx8) and 
>>>> Vega10(gfx9)
>>>>
>>>> In summary, over 1 million WWREG32 in loop with and without this patch you 
>>>> get around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for 
>>>> each WWREG32) for using drm_dev_enter check when writing registers.
>>>>
>>>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.
>>>
>>> Well if I'm not completely mistaken that are 100ms of accumulated overhead. 
>>> So around 100ns per write. And even bigger problem is that this is a ~67% 
>>> increase.
>>
>>
>> My bad, and 67% from what ? How u calculate ?
> 
> My bad, (308501-209689)/209689=47% increase.
> 
>>>
>>> I'm not sure how many write we do during normal operation, but that sounds 
>>> like a bit much. Ideas?
>>
>> Well, u suggested to move the drm_dev_enter way up but as i see it the problem 
>> with this is that it increase the chance of race where the
>> device is extracted after we check for drm_dev_enter (there is also such 
>> chance even when it's placed inside WWREG but it's lower).
>> Earlier I propsed that instead of doing all those guards scattered all over 
>> the code simply delay release of system memory pages and unreserve of
>> MMIO ranges to until after the device itself is gone after last drm device 
>> reference is dropped. But Daniel opposes delaying MMIO ranges unreserve to after
>> PCI remove code because according to him it will upset the PCI subsytem.
> 
> Yeah, that's most likely true as well.
> 
> Maybe Daniel has another idea when he's back from vacation.
> 
> Christian.
> 
>>
>> Andrey
>>
>>>
>>> Christian.
>> _______________________________________________
>> amd-gfx mailing list
>> amd-gfx@lists.freedesktop.org
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7e63c7ba9ac44d80163108d8c48b9507%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637475451078731703%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=SozIYYmHpkk%2B4PRycs8T7x1DYagThy6lQoFXV5Ddamk%3D&amp;reserved=0 
>>
>
Daniel Vetter Feb. 5, 2021, 10:10 p.m. UTC | #14
On Fri, Feb 5, 2021 at 5:22 PM Andrey Grodzovsky
<Andrey.Grodzovsky@amd.com> wrote:
>
> Daniel, ping. Also, please refer to the other thread with Bjorn from pci-dev
> on the same topic I added you to.

Summarizing my take over there for here plus maybe some more
clarification. There's two problems:

- You must guarantee that after the ->remove callback of your driver
is finished, there's no more mmio or any other hw access. A
combination of stopping stuff and drm_dev_enter/exit can help with
that. This prevents the use-after-free issue.

- For the actual hotunplug time, i.e. anything that can run while your
driver is used up to the point where ->remove callback has finished
stopp hw access you must guarantee that code doesn't blow up when it
gets bogus reads (in the form of 0xff values). drm_dev_enter/exit
can't help you with that. Plus you should make sure that we're not
spending forever waiting for a big pile of mmio access all to time out
because you never bail out - some coarse-grained drm_dev_enter/exit
might help here.

Plus finally the userspace access problem: You must guarantee that
after ->remove has finished that none of the uapi or cross-driver
access points (driver ioctl, dma-buf, dma-fence, anything else that
hangs around) can reach the data structures/memory mappings/whatever
which have been released as part of your ->remove callback.
drm_dev_enter/exit is again the tool of choice here.

So you have to use drm_dev_enter/exit for some of the problems we face
on hotunplug, but it's not the tool that can handle the actual hw
hotunplug race conditions for you.

Unfortunately the hw hotunplug race condition is an utter pain to
test, since essentially you need to validate your driver against
spurious 0xff reads at any moment. And I don't even have a clever idea
to simulate this, e.g. by forcefully replacing the iobar mapping: What
we'd need is a mapping that allows reads (so we can fill a page with
0xff and use that everywhere), but instead of rejecting writes, allows
them, but drops them (so that the 0xff stays intact). Maybe we could
simulate this with some kernel debug tricks (kinda like mmiotrace)
with a read-only mapping and dropping every write every time we fault.
But ugh ...

Otoh validating an entire driver like amdgpu without such a trick
against 0xff reads is practically impossible. So maybe you need to add
this as one of the tasks here?
-Daniel

>
> Andrey
>
> On 1/29/21 2:25 PM, Christian König wrote:
> > Am 29.01.21 um 18:35 schrieb Andrey Grodzovsky:
> >>
> >> On 1/29/21 10:16 AM, Christian König wrote:
> >>> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
> >>>>
> >>>> On 1/19/21 1:59 PM, Christian König wrote:
> >>>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
> >>>>>>
> >>>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
> >>>>>>> [SNIP]
> >>>>>> So say writing in a loop to some harmless scratch register for many times
> >>>>>> both for plugged
> >>>>>> and unplugged case and measure total time delta ?
> >>>>>
> >>>>> I think we should at least measure the following:
> >>>>>
> >>>>> 1. Writing X times to a scratch reg without your patch.
> >>>>> 2. Writing X times to a scratch reg with your patch.
> >>>>> 3. Writing X times to a scratch reg with the hardware physically disconnected.
> >>>>>
> >>>>> I suggest to repeat that once for Polaris (or older) and once for Vega or
> >>>>> Navi.
> >>>>>
> >>>>> The SRBM on Polaris is meant to introduce some delay in each access, so it
> >>>>> might react differently then the newer hardware.
> >>>>>
> >>>>> Christian.
> >>>>
> >>>>
> >>>> See attached results and the testing code. Ran on Polaris (gfx8) and
> >>>> Vega10(gfx9)
> >>>>
> >>>> In summary, over 1 million WWREG32 in loop with and without this patch you
> >>>> get around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for
> >>>> each WWREG32) for using drm_dev_enter check when writing registers.
> >>>>
> >>>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.
> >>>
> >>> Well if I'm not completely mistaken that are 100ms of accumulated overhead.
> >>> So around 100ns per write. And even bigger problem is that this is a ~67%
> >>> increase.
> >>
> >>
> >> My bad, and 67% from what ? How u calculate ?
> >
> > My bad, (308501-209689)/209689=47% increase.
> >
> >>>
> >>> I'm not sure how many write we do during normal operation, but that sounds
> >>> like a bit much. Ideas?
> >>
> >> Well, u suggested to move the drm_dev_enter way up but as i see it the problem
> >> with this is that it increase the chance of race where the
> >> device is extracted after we check for drm_dev_enter (there is also such
> >> chance even when it's placed inside WWREG but it's lower).
> >> Earlier I propsed that instead of doing all those guards scattered all over
> >> the code simply delay release of system memory pages and unreserve of
> >> MMIO ranges to until after the device itself is gone after last drm device
> >> reference is dropped. But Daniel opposes delaying MMIO ranges unreserve to after
> >> PCI remove code because according to him it will upset the PCI subsytem.
> >
> > Yeah, that's most likely true as well.
> >
> > Maybe Daniel has another idea when he's back from vacation.
> >
> > Christian.
> >
> >>
> >> Andrey
> >>
> >>>
> >>> Christian.
> >> _______________________________________________
> >> amd-gfx mailing list
> >> amd-gfx@lists.freedesktop.org
> >> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7e63c7ba9ac44d80163108d8c48b9507%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637475451078731703%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=SozIYYmHpkk%2B4PRycs8T7x1DYagThy6lQoFXV5Ddamk%3D&amp;reserved=0
> >>
> >
Andrey Grodzovsky Feb. 5, 2021, 11:09 p.m. UTC | #15
On 2/5/21 5:10 PM, Daniel Vetter wrote:
> On Fri, Feb 5, 2021 at 5:22 PM Andrey Grodzovsky
> <Andrey.Grodzovsky@amd.com> wrote:
>>
>> Daniel, ping. Also, please refer to the other thread with Bjorn from pci-dev
>> on the same topic I added you to.
> 
> Summarizing my take over there for here plus maybe some more
> clarification. There's two problems:
> 
> - You must guarantee that after the ->remove callback of your driver
> is finished, there's no more mmio or any other hw access. A
> combination of stopping stuff and drm_dev_enter/exit can help with
> that. This prevents the use-after-free issue.
> 
> - For the actual hotunplug time, i.e. anything that can run while your
> driver is used up to the point where ->remove callback has finished
> stopp hw access you must guarantee that code doesn't blow up when it
> gets bogus reads (in the form of 0xff values). drm_dev_enter/exit
> can't help you with that. Plus you should make sure that we're not
> spending forever waiting for a big pile of mmio access all to time out
> because you never bail out - some coarse-grained drm_dev_enter/exit
> might help here.
> 
> Plus finally the userspace access problem: You must guarantee that
> after ->remove has finished that none of the uapi or cross-driver
> access points (driver ioctl, dma-buf, dma-fence, anything else that
> hangs around) can reach the data structures/memory mappings/whatever
> which have been released as part of your ->remove callback.
> drm_dev_enter/exit is again the tool of choice here.
> 
> So you have to use drm_dev_enter/exit for some of the problems we face
> on hotunplug, but it's not the tool that can handle the actual hw
> hotunplug race conditions for you.
> 
> Unfortunately the hw hotunplug race condition is an utter pain to
> test, since essentially you need to validate your driver against
> spurious 0xff reads at any moment. And I don't even have a clever idea
> to simulate this, e.g. by forcefully replacing the iobar mapping: What
> we'd need is a mapping that allows reads (so we can fill a page with
> 0xff and use that everywhere), but instead of rejecting writes, allows
> them, but drops them (so that the 0xff stays intact). Maybe we could
> simulate this with some kernel debug tricks (kinda like mmiotrace)
> with a read-only mapping and dropping every write every time we fault.
> But ugh ...
> 
> Otoh validating an entire driver like amdgpu without such a trick
> against 0xff reads is practically impossible. So maybe you need to add
> this as one of the tasks here?
> -Daniel

Not sure it's not a dump idea but still, worth asking -  what if I
just simply quietly return early from the .remove  callback  without
doing anything there, the driver will not be aware that the device
is removed and will at least try to continue working as usual including
IOCTLs, job scheduling e.t.c. On the other hand all MMIO read accesses will
start returning ~0, regarding rejecting writes - I don't see anywhere
we test for result of writing (e.g. amdgpu_mm_wreg8) so seems they will
just seamlessly  go through... Or is it the pci_dev that will be freed
by PCI core itself and so I will immediately crash ?

Andrey

> 
>>
>> Andrey
>>
>> On 1/29/21 2:25 PM, Christian König wrote:
>>> Am 29.01.21 um 18:35 schrieb Andrey Grodzovsky:
>>>>
>>>> On 1/29/21 10:16 AM, Christian König wrote:
>>>>> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
>>>>>>
>>>>>> On 1/19/21 1:59 PM, Christian König wrote:
>>>>>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>>>>>>>
>>>>>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>>>>>>>> [SNIP]
>>>>>>>> So say writing in a loop to some harmless scratch register for many times
>>>>>>>> both for plugged
>>>>>>>> and unplugged case and measure total time delta ?
>>>>>>>
>>>>>>> I think we should at least measure the following:
>>>>>>>
>>>>>>> 1. Writing X times to a scratch reg without your patch.
>>>>>>> 2. Writing X times to a scratch reg with your patch.
>>>>>>> 3. Writing X times to a scratch reg with the hardware physically disconnected.
>>>>>>>
>>>>>>> I suggest to repeat that once for Polaris (or older) and once for Vega or
>>>>>>> Navi.
>>>>>>>
>>>>>>> The SRBM on Polaris is meant to introduce some delay in each access, so it
>>>>>>> might react differently then the newer hardware.
>>>>>>>
>>>>>>> Christian.
>>>>>>
>>>>>>
>>>>>> See attached results and the testing code. Ran on Polaris (gfx8) and
>>>>>> Vega10(gfx9)
>>>>>>
>>>>>> In summary, over 1 million WWREG32 in loop with and without this patch you
>>>>>> get around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for
>>>>>> each WWREG32) for using drm_dev_enter check when writing registers.
>>>>>>
>>>>>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.
>>>>>
>>>>> Well if I'm not completely mistaken that are 100ms of accumulated overhead.
>>>>> So around 100ns per write. And even bigger problem is that this is a ~67%
>>>>> increase.
>>>>
>>>>
>>>> My bad, and 67% from what ? How u calculate ?
>>>
>>> My bad, (308501-209689)/209689=47% increase.
>>>
>>>>>
>>>>> I'm not sure how many write we do during normal operation, but that sounds
>>>>> like a bit much. Ideas?
>>>>
>>>> Well, u suggested to move the drm_dev_enter way up but as i see it the problem
>>>> with this is that it increase the chance of race where the
>>>> device is extracted after we check for drm_dev_enter (there is also such
>>>> chance even when it's placed inside WWREG but it's lower).
>>>> Earlier I propsed that instead of doing all those guards scattered all over
>>>> the code simply delay release of system memory pages and unreserve of
>>>> MMIO ranges to until after the device itself is gone after last drm device
>>>> reference is dropped. But Daniel opposes delaying MMIO ranges unreserve to after
>>>> PCI remove code because according to him it will upset the PCI subsytem.
>>>
>>> Yeah, that's most likely true as well.
>>>
>>> Maybe Daniel has another idea when he's back from vacation.
>>>
>>> Christian.
>>>
>>>>
>>>> Andrey
>>>>
>>>>>
>>>>> Christian.
>>>> _______________________________________________
>>>> amd-gfx mailing list
>>>> amd-gfx@lists.freedesktop.org
>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7810d8d6f03443ce2e0408d8ca22ea99%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637481598615581693%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=zTV6FTpL3titmMTVEPxxVT8e5lTKVsLViwZudEsNn%2Bw%3D&amp;reserved=0
>>>>
>>>
> 
> 
>
Daniel Vetter Feb. 6, 2021, 2:18 p.m. UTC | #16
On Sat, Feb 6, 2021 at 12:09 AM Andrey Grodzovsky
<Andrey.Grodzovsky@amd.com> wrote:
>
>
>
> On 2/5/21 5:10 PM, Daniel Vetter wrote:
> > On Fri, Feb 5, 2021 at 5:22 PM Andrey Grodzovsky
> > <Andrey.Grodzovsky@amd.com> wrote:
> >>
> >> Daniel, ping. Also, please refer to the other thread with Bjorn from pci-dev
> >> on the same topic I added you to.
> >
> > Summarizing my take over there for here plus maybe some more
> > clarification. There's two problems:
> >
> > - You must guarantee that after the ->remove callback of your driver
> > is finished, there's no more mmio or any other hw access. A
> > combination of stopping stuff and drm_dev_enter/exit can help with
> > that. This prevents the use-after-free issue.
> >
> > - For the actual hotunplug time, i.e. anything that can run while your
> > driver is used up to the point where ->remove callback has finished
> > stopp hw access you must guarantee that code doesn't blow up when it
> > gets bogus reads (in the form of 0xff values). drm_dev_enter/exit
> > can't help you with that. Plus you should make sure that we're not
> > spending forever waiting for a big pile of mmio access all to time out
> > because you never bail out - some coarse-grained drm_dev_enter/exit
> > might help here.
> >
> > Plus finally the userspace access problem: You must guarantee that
> > after ->remove has finished that none of the uapi or cross-driver
> > access points (driver ioctl, dma-buf, dma-fence, anything else that
> > hangs around) can reach the data structures/memory mappings/whatever
> > which have been released as part of your ->remove callback.
> > drm_dev_enter/exit is again the tool of choice here.
> >
> > So you have to use drm_dev_enter/exit for some of the problems we face
> > on hotunplug, but it's not the tool that can handle the actual hw
> > hotunplug race conditions for you.
> >
> > Unfortunately the hw hotunplug race condition is an utter pain to
> > test, since essentially you need to validate your driver against
> > spurious 0xff reads at any moment. And I don't even have a clever idea
> > to simulate this, e.g. by forcefully replacing the iobar mapping: What
> > we'd need is a mapping that allows reads (so we can fill a page with
> > 0xff and use that everywhere), but instead of rejecting writes, allows
> > them, but drops them (so that the 0xff stays intact). Maybe we could
> > simulate this with some kernel debug tricks (kinda like mmiotrace)
> > with a read-only mapping and dropping every write every time we fault.
> > But ugh ...
> >
> > Otoh validating an entire driver like amdgpu without such a trick
> > against 0xff reads is practically impossible. So maybe you need to add
> > this as one of the tasks here?
> > -Daniel
>
> Not sure it's not a dump idea but still, worth asking -  what if I
> just simply quietly return early from the .remove  callback  without
> doing anything there, the driver will not be aware that the device
> is removed and will at least try to continue working as usual including
> IOCTLs, job scheduling e.t.c. On the other hand all MMIO read accesses will
> start returning ~0, regarding rejecting writes - I don't see anywhere
> we test for result of writing (e.g. amdgpu_mm_wreg8) so seems they will
> just seamlessly  go through... Or is it the pci_dev that will be freed
> by PCI core itself and so I will immediately crash ?

This still requires that you physically unplug the device, so not
something you can do in CI. Plus it doesn't allow you to easily fake a
hotunplug in the middle of something interesting like an atomic
modeset commit. If you instead punch out the mmio mapping with some
pte trick, you can intercept the faults and count down until you
actually switch over to only returning 0xff. This allows you to sweep
through entire complex execution flows so that you have a guarantee
you've actually caught everything.

If otoh you just hotunplug and don't clean up (or equivalent, insert a
long sleep at the beginning of your ->remove hook) then you just check
that at the beginning of each operation there's a check that bails
out.

It's better than nothing for prototyping, but I don't think it's
useful in a CI setting to assure stuff stays fixed.
-Daniel


> Andrey
>
> >
> >>
> >> Andrey
> >>
> >> On 1/29/21 2:25 PM, Christian König wrote:
> >>> Am 29.01.21 um 18:35 schrieb Andrey Grodzovsky:
> >>>>
> >>>> On 1/29/21 10:16 AM, Christian König wrote:
> >>>>> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
> >>>>>>
> >>>>>> On 1/19/21 1:59 PM, Christian König wrote:
> >>>>>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
> >>>>>>>>
> >>>>>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
> >>>>>>>>> [SNIP]
> >>>>>>>> So say writing in a loop to some harmless scratch register for many times
> >>>>>>>> both for plugged
> >>>>>>>> and unplugged case and measure total time delta ?
> >>>>>>>
> >>>>>>> I think we should at least measure the following:
> >>>>>>>
> >>>>>>> 1. Writing X times to a scratch reg without your patch.
> >>>>>>> 2. Writing X times to a scratch reg with your patch.
> >>>>>>> 3. Writing X times to a scratch reg with the hardware physically disconnected.
> >>>>>>>
> >>>>>>> I suggest to repeat that once for Polaris (or older) and once for Vega or
> >>>>>>> Navi.
> >>>>>>>
> >>>>>>> The SRBM on Polaris is meant to introduce some delay in each access, so it
> >>>>>>> might react differently then the newer hardware.
> >>>>>>>
> >>>>>>> Christian.
> >>>>>>
> >>>>>>
> >>>>>> See attached results and the testing code. Ran on Polaris (gfx8) and
> >>>>>> Vega10(gfx9)
> >>>>>>
> >>>>>> In summary, over 1 million WWREG32 in loop with and without this patch you
> >>>>>> get around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for
> >>>>>> each WWREG32) for using drm_dev_enter check when writing registers.
> >>>>>>
> >>>>>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.
> >>>>>
> >>>>> Well if I'm not completely mistaken that are 100ms of accumulated overhead.
> >>>>> So around 100ns per write. And even bigger problem is that this is a ~67%
> >>>>> increase.
> >>>>
> >>>>
> >>>> My bad, and 67% from what ? How u calculate ?
> >>>
> >>> My bad, (308501-209689)/209689=47% increase.
> >>>
> >>>>>
> >>>>> I'm not sure how many write we do during normal operation, but that sounds
> >>>>> like a bit much. Ideas?
> >>>>
> >>>> Well, u suggested to move the drm_dev_enter way up but as i see it the problem
> >>>> with this is that it increase the chance of race where the
> >>>> device is extracted after we check for drm_dev_enter (there is also such
> >>>> chance even when it's placed inside WWREG but it's lower).
> >>>> Earlier I propsed that instead of doing all those guards scattered all over
> >>>> the code simply delay release of system memory pages and unreserve of
> >>>> MMIO ranges to until after the device itself is gone after last drm device
> >>>> reference is dropped. But Daniel opposes delaying MMIO ranges unreserve to after
> >>>> PCI remove code because according to him it will upset the PCI subsytem.
> >>>
> >>> Yeah, that's most likely true as well.
> >>>
> >>> Maybe Daniel has another idea when he's back from vacation.
> >>>
> >>> Christian.
> >>>
> >>>>
> >>>> Andrey
> >>>>
> >>>>>
> >>>>> Christian.
> >>>> _______________________________________________
> >>>> amd-gfx mailing list
> >>>> amd-gfx@lists.freedesktop.org
> >>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7810d8d6f03443ce2e0408d8ca22ea99%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637481598615581693%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=zTV6FTpL3titmMTVEPxxVT8e5lTKVsLViwZudEsNn%2Bw%3D&amp;reserved=0
> >>>>
> >>>
> >
> >
> >
Andrey Grodzovsky Feb. 7, 2021, 9:28 p.m. UTC | #17
On 2/5/21 5:10 PM, Daniel Vetter wrote:
> On Fri, Feb 5, 2021 at 5:22 PM Andrey Grodzovsky
> <Andrey.Grodzovsky@amd.com> wrote:
>>
>> Daniel, ping. Also, please refer to the other thread with Bjorn from pci-dev
>> on the same topic I added you to.
> 
> Summarizing my take over there for here plus maybe some more
> clarification. There's two problems:
> 
> - You must guarantee that after the ->remove callback of your driver
> is finished, there's no more mmio or any other hw access. A
> combination of stopping stuff and drm_dev_enter/exit can help with
> that. This prevents the use-after-free issue.
> 
> - For the actual hotunplug time, i.e. anything that can run while your
> driver is used up to the point where ->remove callback has finished
> stopp hw access you must guarantee that code doesn't blow up when it
> gets bogus reads (in the form of 0xff values). drm_dev_enter/exit
> can't help you with that. Plus you should make sure that we're not
> spending forever waiting for a big pile of mmio access all to time out
> because you never bail out - some coarse-grained drm_dev_enter/exit
> might help here.
> 
> Plus finally the userspace access problem: You must guarantee that
> after ->remove has finished that none of the uapi or cross-driver
> access points (driver ioctl, dma-buf, dma-fence, anything else that
> hangs around) can reach the data structures/memory mappings/whatever
> which have been released as part of your ->remove callback.
> drm_dev_enter/exit is again the tool of choice here.
> 
> So you have to use drm_dev_enter/exit for some of the problems we face
> on hotunplug, but it's not the tool that can handle the actual hw
> hotunplug race conditions for you.
> 
> Unfortunately the hw hotunplug race condition is an utter pain to
> test, since essentially you need to validate your driver against
> spurious 0xff reads at any moment. And I don't even have a clever idea
> to simulate this, e.g. by forcefully replacing the iobar mapping: What
> we'd need is a mapping that allows reads (so we can fill a page with
> 0xff and use that everywhere), but instead of rejecting writes, allows
> them, but drops them (so that the 0xff stays intact). Maybe we could
> simulate this with some kernel debug tricks (kinda like mmiotrace)
> with a read-only mapping and dropping every write every time we fault.

Clarification - as far as I know there are no page fault handlers for kernel
mappings. And we are talking about kernel mappings here, right ?  If there were 
I could solve all those issues the same as I do for user mappings, by
invalidating all existing mappings in the kernel (both kmaps and ioreamps)and 
insert dummy zero or ~0 filled page instead.
Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
ioremap API and it's not something that I think can be easily done according to
am answer i got to a related topic a few weeks ago 
https://www.spinics.net/lists/linux-pci/msg103396.html (that was the only reply 
i got)


> But ugh ...
> 
> Otoh validating an entire driver like amdgpu without such a trick
> against 0xff reads is practically impossible. So maybe you need to add
> this as one of the tasks here?

Or I could just for validation purposes return ~0 from all reg reads in the code
and ignore writes if drm_dev_unplugged, this could already easily validate a big 
portion of the code flow under such scenario.

Andrey

> -Daniel
> 
>>
>> Andrey
>>
>> On 1/29/21 2:25 PM, Christian König wrote:
>>> Am 29.01.21 um 18:35 schrieb Andrey Grodzovsky:
>>>>
>>>> On 1/29/21 10:16 AM, Christian König wrote:
>>>>> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
>>>>>>
>>>>>> On 1/19/21 1:59 PM, Christian König wrote:
>>>>>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
>>>>>>>>
>>>>>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
>>>>>>>>> [SNIP]
>>>>>>>> So say writing in a loop to some harmless scratch register for many times
>>>>>>>> both for plugged
>>>>>>>> and unplugged case and measure total time delta ?
>>>>>>>
>>>>>>> I think we should at least measure the following:
>>>>>>>
>>>>>>> 1. Writing X times to a scratch reg without your patch.
>>>>>>> 2. Writing X times to a scratch reg with your patch.
>>>>>>> 3. Writing X times to a scratch reg with the hardware physically disconnected.
>>>>>>>
>>>>>>> I suggest to repeat that once for Polaris (or older) and once for Vega or
>>>>>>> Navi.
>>>>>>>
>>>>>>> The SRBM on Polaris is meant to introduce some delay in each access, so it
>>>>>>> might react differently then the newer hardware.
>>>>>>>
>>>>>>> Christian.
>>>>>>
>>>>>>
>>>>>> See attached results and the testing code. Ran on Polaris (gfx8) and
>>>>>> Vega10(gfx9)
>>>>>>
>>>>>> In summary, over 1 million WWREG32 in loop with and without this patch you
>>>>>> get around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for
>>>>>> each WWREG32) for using drm_dev_enter check when writing registers.
>>>>>>
>>>>>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.
>>>>>
>>>>> Well if I'm not completely mistaken that are 100ms of accumulated overhead.
>>>>> So around 100ns per write. And even bigger problem is that this is a ~67%
>>>>> increase.
>>>>
>>>>
>>>> My bad, and 67% from what ? How u calculate ?
>>>
>>> My bad, (308501-209689)/209689=47% increase.
>>>
>>>>>
>>>>> I'm not sure how many write we do during normal operation, but that sounds
>>>>> like a bit much. Ideas?
>>>>
>>>> Well, u suggested to move the drm_dev_enter way up but as i see it the problem
>>>> with this is that it increase the chance of race where the
>>>> device is extracted after we check for drm_dev_enter (there is also such
>>>> chance even when it's placed inside WWREG but it's lower).
>>>> Earlier I propsed that instead of doing all those guards scattered all over
>>>> the code simply delay release of system memory pages and unreserve of
>>>> MMIO ranges to until after the device itself is gone after last drm device
>>>> reference is dropped. But Daniel opposes delaying MMIO ranges unreserve to after
>>>> PCI remove code because according to him it will upset the PCI subsytem.
>>>
>>> Yeah, that's most likely true as well.
>>>
>>> Maybe Daniel has another idea when he's back from vacation.
>>>
>>> Christian.
>>>
>>>>
>>>> Andrey
>>>>
>>>>>
>>>>> Christian.
>>>> _______________________________________________
>>>> amd-gfx mailing list
>>>> amd-gfx@lists.freedesktop.org
>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7810d8d6f03443ce2e0408d8ca22ea99%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637481598615581693%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=zTV6FTpL3titmMTVEPxxVT8e5lTKVsLViwZudEsNn%2Bw%3D&amp;reserved=0
>>>>
>>>
> 
> 
>
Daniel Vetter Feb. 7, 2021, 9:50 p.m. UTC | #18
On Sun, Feb 7, 2021 at 10:28 PM Andrey Grodzovsky
<Andrey.Grodzovsky@amd.com> wrote:
>
>
>
> On 2/5/21 5:10 PM, Daniel Vetter wrote:
> > On Fri, Feb 5, 2021 at 5:22 PM Andrey Grodzovsky
> > <Andrey.Grodzovsky@amd.com> wrote:
> >>
> >> Daniel, ping. Also, please refer to the other thread with Bjorn from pci-dev
> >> on the same topic I added you to.
> >
> > Summarizing my take over there for here plus maybe some more
> > clarification. There's two problems:
> >
> > - You must guarantee that after the ->remove callback of your driver
> > is finished, there's no more mmio or any other hw access. A
> > combination of stopping stuff and drm_dev_enter/exit can help with
> > that. This prevents the use-after-free issue.
> >
> > - For the actual hotunplug time, i.e. anything that can run while your
> > driver is used up to the point where ->remove callback has finished
> > stopp hw access you must guarantee that code doesn't blow up when it
> > gets bogus reads (in the form of 0xff values). drm_dev_enter/exit
> > can't help you with that. Plus you should make sure that we're not
> > spending forever waiting for a big pile of mmio access all to time out
> > because you never bail out - some coarse-grained drm_dev_enter/exit
> > might help here.
> >
> > Plus finally the userspace access problem: You must guarantee that
> > after ->remove has finished that none of the uapi or cross-driver
> > access points (driver ioctl, dma-buf, dma-fence, anything else that
> > hangs around) can reach the data structures/memory mappings/whatever
> > which have been released as part of your ->remove callback.
> > drm_dev_enter/exit is again the tool of choice here.
> >
> > So you have to use drm_dev_enter/exit for some of the problems we face
> > on hotunplug, but it's not the tool that can handle the actual hw
> > hotunplug race conditions for you.
> >
> > Unfortunately the hw hotunplug race condition is an utter pain to
> > test, since essentially you need to validate your driver against
> > spurious 0xff reads at any moment. And I don't even have a clever idea
> > to simulate this, e.g. by forcefully replacing the iobar mapping: What
> > we'd need is a mapping that allows reads (so we can fill a page with
> > 0xff and use that everywhere), but instead of rejecting writes, allows
> > them, but drops them (so that the 0xff stays intact). Maybe we could
> > simulate this with some kernel debug tricks (kinda like mmiotrace)
> > with a read-only mapping and dropping every write every time we fault.
>
> Clarification - as far as I know there are no page fault handlers for kernel
> mappings. And we are talking about kernel mappings here, right ?  If there were
> I could solve all those issues the same as I do for user mappings, by
> invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
> insert dummy zero or ~0 filled page instead.
> Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
> ioremap API and it's not something that I think can be easily done according to
> am answer i got to a related topic a few weeks ago
> https://www.spinics.net/lists/linux-pci/msg103396.html (that was the only reply
> i got)

mmiotrace can, but only for debug, and only on x86 platforms:

https://www.kernel.org/doc/html/latest/trace/mmiotrace.html

Should be feasible (but maybe not worth the effort) to extend this to
support fake unplug.

>
> > But ugh ...
> >
> > Otoh validating an entire driver like amdgpu without such a trick
> > against 0xff reads is practically impossible. So maybe you need to add
> > this as one of the tasks here?
>
> Or I could just for validation purposes return ~0 from all reg reads in the code
> and ignore writes if drm_dev_unplugged, this could already easily validate a big
> portion of the code flow under such scenario.

Hm yeah if your really wrap them all, that should work too. Since
iommappings have __iomem pointer type, as long as amdgpu is sparse
warning free, should be doable to guarantee this.
-Daniel

> Andrey
>
> > -Daniel
> >
> >>
> >> Andrey
> >>
> >> On 1/29/21 2:25 PM, Christian König wrote:
> >>> Am 29.01.21 um 18:35 schrieb Andrey Grodzovsky:
> >>>>
> >>>> On 1/29/21 10:16 AM, Christian König wrote:
> >>>>> Am 28.01.21 um 18:23 schrieb Andrey Grodzovsky:
> >>>>>>
> >>>>>> On 1/19/21 1:59 PM, Christian König wrote:
> >>>>>>> Am 19.01.21 um 19:22 schrieb Andrey Grodzovsky:
> >>>>>>>>
> >>>>>>>> On 1/19/21 1:05 PM, Daniel Vetter wrote:
> >>>>>>>>> [SNIP]
> >>>>>>>> So say writing in a loop to some harmless scratch register for many times
> >>>>>>>> both for plugged
> >>>>>>>> and unplugged case and measure total time delta ?
> >>>>>>>
> >>>>>>> I think we should at least measure the following:
> >>>>>>>
> >>>>>>> 1. Writing X times to a scratch reg without your patch.
> >>>>>>> 2. Writing X times to a scratch reg with your patch.
> >>>>>>> 3. Writing X times to a scratch reg with the hardware physically disconnected.
> >>>>>>>
> >>>>>>> I suggest to repeat that once for Polaris (or older) and once for Vega or
> >>>>>>> Navi.
> >>>>>>>
> >>>>>>> The SRBM on Polaris is meant to introduce some delay in each access, so it
> >>>>>>> might react differently then the newer hardware.
> >>>>>>>
> >>>>>>> Christian.
> >>>>>>
> >>>>>>
> >>>>>> See attached results and the testing code. Ran on Polaris (gfx8) and
> >>>>>> Vega10(gfx9)
> >>>>>>
> >>>>>> In summary, over 1 million WWREG32 in loop with and without this patch you
> >>>>>> get around 10ms of accumulated overhead ( so 0.00001 millisecond penalty for
> >>>>>> each WWREG32) for using drm_dev_enter check when writing registers.
> >>>>>>
> >>>>>> P.S Bullet 3 I cannot test as I need eGPU and currently I don't have one.
> >>>>>
> >>>>> Well if I'm not completely mistaken that are 100ms of accumulated overhead.
> >>>>> So around 100ns per write. And even bigger problem is that this is a ~67%
> >>>>> increase.
> >>>>
> >>>>
> >>>> My bad, and 67% from what ? How u calculate ?
> >>>
> >>> My bad, (308501-209689)/209689=47% increase.
> >>>
> >>>>>
> >>>>> I'm not sure how many write we do during normal operation, but that sounds
> >>>>> like a bit much. Ideas?
> >>>>
> >>>> Well, u suggested to move the drm_dev_enter way up but as i see it the problem
> >>>> with this is that it increase the chance of race where the
> >>>> device is extracted after we check for drm_dev_enter (there is also such
> >>>> chance even when it's placed inside WWREG but it's lower).
> >>>> Earlier I propsed that instead of doing all those guards scattered all over
> >>>> the code simply delay release of system memory pages and unreserve of
> >>>> MMIO ranges to until after the device itself is gone after last drm device
> >>>> reference is dropped. But Daniel opposes delaying MMIO ranges unreserve to after
> >>>> PCI remove code because according to him it will upset the PCI subsytem.
> >>>
> >>> Yeah, that's most likely true as well.
> >>>
> >>> Maybe Daniel has another idea when he's back from vacation.
> >>>
> >>> Christian.
> >>>
> >>>>
> >>>> Andrey
> >>>>
> >>>>>
> >>>>> Christian.
> >>>> _______________________________________________
> >>>> amd-gfx mailing list
> >>>> amd-gfx@lists.freedesktop.org
> >>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C7810d8d6f03443ce2e0408d8ca22ea99%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637481598615581693%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=zTV6FTpL3titmMTVEPxxVT8e5lTKVsLViwZudEsNn%2Bw%3D&amp;reserved=0
> >>>>
> >>>
> >
> >
> >
Christian König Feb. 8, 2021, 9:37 a.m. UTC | #19
Am 07.02.21 um 22:50 schrieb Daniel Vetter:
> [SNIP]
>> Clarification - as far as I know there are no page fault handlers for kernel
>> mappings. And we are talking about kernel mappings here, right ?  If there were
>> I could solve all those issues the same as I do for user mappings, by
>> invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
>> insert dummy zero or ~0 filled page instead.
>> Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
>> ioremap API and it's not something that I think can be easily done according to
>> am answer i got to a related topic a few weeks ago
>> https://www.spinics.net/lists/linux-pci/msg103396.html (that was the only reply
>> i got)
> mmiotrace can, but only for debug, and only on x86 platforms:
>
> https://www.kernel.org/doc/html/latest/trace/mmiotrace.html
>
> Should be feasible (but maybe not worth the effort) to extend this to
> support fake unplug.

Mhm, interesting idea you guys brought up here.

We don't need a page fault for this to work, all we need to do is to 
insert dummy PTEs into the kernels page table at the place where 
previously the MMIO mapping has been.

>>> But ugh ...
>>>
>>> Otoh validating an entire driver like amdgpu without such a trick
>>> against 0xff reads is practically impossible. So maybe you need to add
>>> this as one of the tasks here?
>> Or I could just for validation purposes return ~0 from all reg reads in the code
>> and ignore writes if drm_dev_unplugged, this could already easily validate a big
>> portion of the code flow under such scenario.
> Hm yeah if your really wrap them all, that should work too. Since
> iommappings have __iomem pointer type, as long as amdgpu is sparse
> warning free, should be doable to guarantee this.

Problem is that ~0 is not always a valid register value.

You would need to audit every register read that it doesn't use the 
returned value blindly as index or similar. That is quite a bit of work.

Regards,
Christian.

> -Daniel
>
>> Andrey
>>
Daniel Vetter Feb. 8, 2021, 9:48 a.m. UTC | #20
On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
> > [SNIP]
> > > Clarification - as far as I know there are no page fault handlers for kernel
> > > mappings. And we are talking about kernel mappings here, right ?  If there were
> > > I could solve all those issues the same as I do for user mappings, by
> > > invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
> > > insert dummy zero or ~0 filled page instead.
> > > Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
> > > ioremap API and it's not something that I think can be easily done according to
> > > am answer i got to a related topic a few weeks ago
> > > https://www.spinics.net/lists/linux-pci/msg103396.html (that was the only reply
> > > i got)
> > mmiotrace can, but only for debug, and only on x86 platforms:
> > 
> > https://www.kernel.org/doc/html/latest/trace/mmiotrace.html
> > 
> > Should be feasible (but maybe not worth the effort) to extend this to
> > support fake unplug.
> 
> Mhm, interesting idea you guys brought up here.
> 
> We don't need a page fault for this to work, all we need to do is to insert
> dummy PTEs into the kernels page table at the place where previously the
> MMIO mapping has been.

Simply pte trick isn't enough, because we need:
- drop all writes silently
- all reads return 0xff

ptes can't do that themselves, we minimally need write protection and then
silently proceed on each write fault without restarting the instruction.
Better would be to only catch reads, but x86 doesn't do write-only pte
permissions afaik.

> > > > But ugh ...
> > > > 
> > > > Otoh validating an entire driver like amdgpu without such a trick
> > > > against 0xff reads is practically impossible. So maybe you need to add
> > > > this as one of the tasks here?
> > > Or I could just for validation purposes return ~0 from all reg reads in the code
> > > and ignore writes if drm_dev_unplugged, this could already easily validate a big
> > > portion of the code flow under such scenario.
> > Hm yeah if your really wrap them all, that should work too. Since
> > iommappings have __iomem pointer type, as long as amdgpu is sparse
> > warning free, should be doable to guarantee this.
> 
> Problem is that ~0 is not always a valid register value.
> 
> You would need to audit every register read that it doesn't use the returned
> value blindly as index or similar. That is quite a bit of work.

Yeah that's the entire crux here :-/
-Daniel
Christian König Feb. 8, 2021, 10:03 a.m. UTC | #21
Am 08.02.21 um 10:48 schrieb Daniel Vetter:
> On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
>> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
>>> [SNIP]
>>>> Clarification - as far as I know there are no page fault handlers for kernel
>>>> mappings. And we are talking about kernel mappings here, right ?  If there were
>>>> I could solve all those issues the same as I do for user mappings, by
>>>> invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
>>>> insert dummy zero or ~0 filled page instead.
>>>> Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
>>>> ioremap API and it's not something that I think can be easily done according to
>>>> am answer i got to a related topic a few weeks ago
>>>> https://www.spinics.net/lists/linux-pci/msg103396.html (that was the only reply
>>>> i got)
>>> mmiotrace can, but only for debug, and only on x86 platforms:
>>>
>>> https://www.kernel.org/doc/html/latest/trace/mmiotrace.html
>>>
>>> Should be feasible (but maybe not worth the effort) to extend this to
>>> support fake unplug.
>> Mhm, interesting idea you guys brought up here.
>>
>> We don't need a page fault for this to work, all we need to do is to insert
>> dummy PTEs into the kernels page table at the place where previously the
>> MMIO mapping has been.
> Simply pte trick isn't enough, because we need:
> - drop all writes silently
> - all reads return 0xff
>
> ptes can't do that themselves, we minimally need write protection and then
> silently proceed on each write fault without restarting the instruction.
> Better would be to only catch reads, but x86 doesn't do write-only pte
> permissions afaik.

You are not thinking far enough :)

The dummy PTE is point to a dummy MMIO page which is just never used.

That hast the exact same properties than our removed MMIO space just 
doesn't goes bananas when a new device is MMIO mapped into that and our 
driver still tries to write there.

Regards,
Christian.


>
>>>>> But ugh ...
>>>>>
>>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>>> against 0xff reads is practically impossible. So maybe you need to add
>>>>> this as one of the tasks here?
>>>> Or I could just for validation purposes return ~0 from all reg reads in the code
>>>> and ignore writes if drm_dev_unplugged, this could already easily validate a big
>>>> portion of the code flow under such scenario.
>>> Hm yeah if your really wrap them all, that should work too. Since
>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>> warning free, should be doable to guarantee this.
>> Problem is that ~0 is not always a valid register value.
>>
>> You would need to audit every register read that it doesn't use the returned
>> value blindly as index or similar. That is quite a bit of work.
> Yeah that's the entire crux here :-/
> -Daniel
Daniel Vetter Feb. 8, 2021, 10:11 a.m. UTC | #22
On Mon, Feb 08, 2021 at 11:03:15AM +0100, Christian König wrote:
> Am 08.02.21 um 10:48 schrieb Daniel Vetter:
> > On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
> > > Am 07.02.21 um 22:50 schrieb Daniel Vetter:
> > > > [SNIP]
> > > > > Clarification - as far as I know there are no page fault handlers for kernel
> > > > > mappings. And we are talking about kernel mappings here, right ?  If there were
> > > > > I could solve all those issues the same as I do for user mappings, by
> > > > > invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
> > > > > insert dummy zero or ~0 filled page instead.
> > > > > Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
> > > > > ioremap API and it's not something that I think can be easily done according to
> > > > > am answer i got to a related topic a few weeks ago
> > > > > https://www.spinics.net/lists/linux-pci/msg103396.html (that was the only reply
> > > > > i got)
> > > > mmiotrace can, but only for debug, and only on x86 platforms:
> > > > 
> > > > https://www.kernel.org/doc/html/latest/trace/mmiotrace.html
> > > > 
> > > > Should be feasible (but maybe not worth the effort) to extend this to
> > > > support fake unplug.
> > > Mhm, interesting idea you guys brought up here.
> > > 
> > > We don't need a page fault for this to work, all we need to do is to insert
> > > dummy PTEs into the kernels page table at the place where previously the
> > > MMIO mapping has been.
> > Simply pte trick isn't enough, because we need:
> > - drop all writes silently
> > - all reads return 0xff
> > 
> > ptes can't do that themselves, we minimally need write protection and then
> > silently proceed on each write fault without restarting the instruction.
> > Better would be to only catch reads, but x86 doesn't do write-only pte
> > permissions afaik.
> 
> You are not thinking far enough :)
> 
> The dummy PTE is point to a dummy MMIO page which is just never used.
> 
> That hast the exact same properties than our removed MMIO space just doesn't
> goes bananas when a new device is MMIO mapped into that and our driver still
> tries to write there.

Hm, but where do we get such a "guaranteed never used" mmio page from?

It's a nifty idea indeed otherwise ...
-Daniel

> 
> Regards,
> Christian.
> 
> 
> > 
> > > > > > But ugh ...
> > > > > > 
> > > > > > Otoh validating an entire driver like amdgpu without such a trick
> > > > > > against 0xff reads is practically impossible. So maybe you need to add
> > > > > > this as one of the tasks here?
> > > > > Or I could just for validation purposes return ~0 from all reg reads in the code
> > > > > and ignore writes if drm_dev_unplugged, this could already easily validate a big
> > > > > portion of the code flow under such scenario.
> > > > Hm yeah if your really wrap them all, that should work too. Since
> > > > iommappings have __iomem pointer type, as long as amdgpu is sparse
> > > > warning free, should be doable to guarantee this.
> > > Problem is that ~0 is not always a valid register value.
> > > 
> > > You would need to audit every register read that it doesn't use the returned
> > > value blindly as index or similar. That is quite a bit of work.
> > Yeah that's the entire crux here :-/
> > -Daniel
>
Christian König Feb. 8, 2021, 1:59 p.m. UTC | #23
Am 08.02.21 um 11:11 schrieb Daniel Vetter:
> On Mon, Feb 08, 2021 at 11:03:15AM +0100, Christian König wrote:
>> Am 08.02.21 um 10:48 schrieb Daniel Vetter:
>>> On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
>>>> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
>>>>> [SNIP]
>>>>>> Clarification - as far as I know there are no page fault handlers for kernel
>>>>>> mappings. And we are talking about kernel mappings here, right ?  If there were
>>>>>> I could solve all those issues the same as I do for user mappings, by
>>>>>> invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
>>>>>> insert dummy zero or ~0 filled page instead.
>>>>>> Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
>>>>>> ioremap API and it's not something that I think can be easily done according to
>>>>>> am answer i got to a related topic a few weeks ago
>>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0ab6d16bc49443d7dd2708d8cc19f3aa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483759137213247%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=mLqR3PoMBvOodcNJA6K6XP1AJ7hiz847y%2Bw%2BcGegSZE%3D&amp;reserved=0 (that was the only reply
>>>>>> i got)
>>>>> mmiotrace can, but only for debug, and only on x86 platforms:
>>>>>
>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0ab6d16bc49443d7dd2708d8cc19f3aa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483759137213247%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=yjEaR73m8rjL4ARo0upHnjSAtE4yw%2BHAISWCSgmjOoY%3D&amp;reserved=0
>>>>>
>>>>> Should be feasible (but maybe not worth the effort) to extend this to
>>>>> support fake unplug.
>>>> Mhm, interesting idea you guys brought up here.
>>>>
>>>> We don't need a page fault for this to work, all we need to do is to insert
>>>> dummy PTEs into the kernels page table at the place where previously the
>>>> MMIO mapping has been.
>>> Simply pte trick isn't enough, because we need:
>>> - drop all writes silently
>>> - all reads return 0xff
>>>
>>> ptes can't do that themselves, we minimally need write protection and then
>>> silently proceed on each write fault without restarting the instruction.
>>> Better would be to only catch reads, but x86 doesn't do write-only pte
>>> permissions afaik.
>> You are not thinking far enough :)
>>
>> The dummy PTE is point to a dummy MMIO page which is just never used.
>>
>> That hast the exact same properties than our removed MMIO space just doesn't
>> goes bananas when a new device is MMIO mapped into that and our driver still
>> tries to write there.
> Hm, but where do we get such a "guaranteed never used" mmio page from?

Well we have tons of unused IO space on 64bit systems these days.

Doesn't really needs to be PCIe address space, doesn't it?

Christian.

>
> It's a nifty idea indeed otherwise ...
> -Daniel
>
>> Regards,
>> Christian.
>>
>>
>>>>>>> But ugh ...
>>>>>>>
>>>>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>>>>> against 0xff reads is practically impossible. So maybe you need to add
>>>>>>> this as one of the tasks here?
>>>>>> Or I could just for validation purposes return ~0 from all reg reads in the code
>>>>>> and ignore writes if drm_dev_unplugged, this could already easily validate a big
>>>>>> portion of the code flow under such scenario.
>>>>> Hm yeah if your really wrap them all, that should work too. Since
>>>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>>>> warning free, should be doable to guarantee this.
>>>> Problem is that ~0 is not always a valid register value.
>>>>
>>>> You would need to audit every register read that it doesn't use the returned
>>>> value blindly as index or similar. That is quite a bit of work.
>>> Yeah that's the entire crux here :-/
>>> -Daniel
Daniel Vetter Feb. 8, 2021, 4:23 p.m. UTC | #24
On Mon, Feb 8, 2021 at 3:00 PM Christian König <christian.koenig@amd.com> wrote:
>
> Am 08.02.21 um 11:11 schrieb Daniel Vetter:
> > On Mon, Feb 08, 2021 at 11:03:15AM +0100, Christian König wrote:
> >> Am 08.02.21 um 10:48 schrieb Daniel Vetter:
> >>> On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
> >>>> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
> >>>>> [SNIP]
> >>>>>> Clarification - as far as I know there are no page fault handlers for kernel
> >>>>>> mappings. And we are talking about kernel mappings here, right ?  If there were
> >>>>>> I could solve all those issues the same as I do for user mappings, by
> >>>>>> invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
> >>>>>> insert dummy zero or ~0 filled page instead.
> >>>>>> Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
> >>>>>> ioremap API and it's not something that I think can be easily done according to
> >>>>>> am answer i got to a related topic a few weeks ago
> >>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0ab6d16bc49443d7dd2708d8cc19f3aa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483759137213247%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=mLqR3PoMBvOodcNJA6K6XP1AJ7hiz847y%2Bw%2BcGegSZE%3D&amp;reserved=0 (that was the only reply
> >>>>>> i got)
> >>>>> mmiotrace can, but only for debug, and only on x86 platforms:
> >>>>>
> >>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0ab6d16bc49443d7dd2708d8cc19f3aa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483759137213247%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=yjEaR73m8rjL4ARo0upHnjSAtE4yw%2BHAISWCSgmjOoY%3D&amp;reserved=0
> >>>>>
> >>>>> Should be feasible (but maybe not worth the effort) to extend this to
> >>>>> support fake unplug.
> >>>> Mhm, interesting idea you guys brought up here.
> >>>>
> >>>> We don't need a page fault for this to work, all we need to do is to insert
> >>>> dummy PTEs into the kernels page table at the place where previously the
> >>>> MMIO mapping has been.
> >>> Simply pte trick isn't enough, because we need:
> >>> - drop all writes silently
> >>> - all reads return 0xff
> >>>
> >>> ptes can't do that themselves, we minimally need write protection and then
> >>> silently proceed on each write fault without restarting the instruction.
> >>> Better would be to only catch reads, but x86 doesn't do write-only pte
> >>> permissions afaik.
> >> You are not thinking far enough :)
> >>
> >> The dummy PTE is point to a dummy MMIO page which is just never used.
> >>
> >> That hast the exact same properties than our removed MMIO space just doesn't
> >> goes bananas when a new device is MMIO mapped into that and our driver still
> >> tries to write there.
> > Hm, but where do we get such a "guaranteed never used" mmio page from?
>
> Well we have tons of unused IO space on 64bit systems these days.
>
> Doesn't really needs to be PCIe address space, doesn't it?

That sounds very trusting to modern systems not decoding random
ranges. E.g. the pci code stopped extending the host bridge windows on
its own, entirely relying on the acpi provided ranges, to avoid
stomping on stuff that's the but not listed anywhere.

I guess if we have a range behind a pci bridge, which isn't used by
any device, but decoded by the bridge, then that should be safe
enough. Maybe could even have an option in upstream to do that on
unplug, if a certain flag is set, or a cmdline option.
-Daniel

>
> Christian.
>
> >
> > It's a nifty idea indeed otherwise ...
> > -Daniel
> >
> >> Regards,
> >> Christian.
> >>
> >>
> >>>>>>> But ugh ...
> >>>>>>>
> >>>>>>> Otoh validating an entire driver like amdgpu without such a trick
> >>>>>>> against 0xff reads is practically impossible. So maybe you need to add
> >>>>>>> this as one of the tasks here?
> >>>>>> Or I could just for validation purposes return ~0 from all reg reads in the code
> >>>>>> and ignore writes if drm_dev_unplugged, this could already easily validate a big
> >>>>>> portion of the code flow under such scenario.
> >>>>> Hm yeah if your really wrap them all, that should work too. Since
> >>>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
> >>>>> warning free, should be doable to guarantee this.
> >>>> Problem is that ~0 is not always a valid register value.
> >>>>
> >>>> You would need to audit every register read that it doesn't use the returned
> >>>> value blindly as index or similar. That is quite a bit of work.
> >>> Yeah that's the entire crux here :-/
> >>> -Daniel
>
Andrey Grodzovsky Feb. 8, 2021, 10:09 p.m. UTC | #25
On 2/8/21 4:37 AM, Christian König wrote:
> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
>> [SNIP]
>>> Clarification - as far as I know there are no page fault handlers for kernel
>>> mappings. And we are talking about kernel mappings here, right ?  If there were
>>> I could solve all those issues the same as I do for user mappings, by
>>> invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
>>> insert dummy zero or ~0 filled page instead.
>>> Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
>>> ioremap API and it's not something that I think can be easily done according to
>>> am answer i got to a related topic a few weeks ago
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cb159d3ce264944486c8008d8cc15233a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483738446813868%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=6eP0nhS%2BZwp1Y54CwfX8vaV3FTWbW8IylW5JFaf92pY%3D&amp;reserved=0 
>>> (that was the only reply
>>> i got)
>> mmiotrace can, but only for debug, and only on x86 platforms:
>>
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cb159d3ce264944486c8008d8cc15233a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483738446813868%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=QBF9J%2BVIRUkUTTjvNoZR8NqFNt8CpHkcknH2qKX7dd8%3D&amp;reserved=0 
>>
>>
>> Should be feasible (but maybe not worth the effort) to extend this to
>> support fake unplug.
>
> Mhm, interesting idea you guys brought up here.
>
> We don't need a page fault for this to work, all we need to do is to insert 
> dummy PTEs into the kernels page table at the place where previously the MMIO 
> mapping has been.


But that exactly what Mathew from linux-mm says is not a trivial thing to do, quote:

"

ioremap() is done through the vmalloc space.  It would, in theory, be
possible to reprogram the page tables used for vmalloc to point to your
magic page.  I don't think we have such a mechanism today, and there are
lots of problems with things like TLB flushes.  It's probably going to
be harder than you think.
"

If you believe it's actually doable then it would be useful not only for simulating device
unplugged situation with all MMIOs returning 0xff... but for actual handling of driver accesses
to MMIO after device is gone and, we could then drop entirely this patch as there would be no need
to guard against such accesses post device unplug.

  

>
>>>> But ugh ...
>>>>
>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>> against 0xff reads is practically impossible. So maybe you need to add
>>>> this as one of the tasks here?
>>> Or I could just for validation purposes return ~0 from all reg reads in the 
>>> code
>>> and ignore writes if drm_dev_unplugged, this could already easily validate a 
>>> big
>>> portion of the code flow under such scenario.
>> Hm yeah if your really wrap them all, that should work too. Since
>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>> warning free, should be doable to guarantee this.
>
> Problem is that ~0 is not always a valid register value.
>
> You would need to audit every register read that it doesn't use the returned 
> value blindly as index or similar. That is quite a bit of work.


But ~0 is the value that will be returned for every read post device unplug, 
regardless if it's valid or not, and we have to cope with
it then, no ?

Andrey


>
> Regards,
> Christian.
>
>> -Daniel
>>
>>> Andrey
>>>
>
Andrey Grodzovsky Feb. 8, 2021, 10:15 p.m. UTC | #26
On 2/8/21 11:23 AM, Daniel Vetter wrote:
> On Mon, Feb 8, 2021 at 3:00 PM Christian König <christian.koenig@amd.com> wrote:
>> Am 08.02.21 um 11:11 schrieb Daniel Vetter:
>>> On Mon, Feb 08, 2021 at 11:03:15AM +0100, Christian König wrote:
>>>> Am 08.02.21 um 10:48 schrieb Daniel Vetter:
>>>>> On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
>>>>>> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
>>>>>>> [SNIP]
>>>>>>>> Clarification - as far as I know there are no page fault handlers for kernel
>>>>>>>> mappings. And we are talking about kernel mappings here, right ?  If there were
>>>>>>>> I could solve all those issues the same as I do for user mappings, by
>>>>>>>> invalidating all existing mappings in the kernel (both kmaps and ioreamps)and
>>>>>>>> insert dummy zero or ~0 filled page instead.
>>>>>>>> Also, I assume forcefully remapping the IO BAR to ~0 filled page would involve
>>>>>>>> ioremap API and it's not something that I think can be easily done according to
>>>>>>>> am answer i got to a related topic a few weeks ago
>>>>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C9d1bdf4cee504cd71b4908d8cc4df310%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483982454608249%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=Anw%2BOwJ%2B5tvjW3tmkVNdz13%2BZ18vdpfOLWqsUZL7D2I%3D&amp;reserved=0 (that was the only reply
>>>>>>>> i got)
>>>>>>> mmiotrace can, but only for debug, and only on x86 platforms:
>>>>>>>
>>>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C9d1bdf4cee504cd71b4908d8cc4df310%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483982454608249%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=Wa7BFNySVQJLyD6WY4pZHTP1QfeZwD7F5ydBrXuxppQ%3D&amp;reserved=0
>>>>>>>
>>>>>>> Should be feasible (but maybe not worth the effort) to extend this to
>>>>>>> support fake unplug.
>>>>>> Mhm, interesting idea you guys brought up here.
>>>>>>
>>>>>> We don't need a page fault for this to work, all we need to do is to insert
>>>>>> dummy PTEs into the kernels page table at the place where previously the
>>>>>> MMIO mapping has been.
>>>>> Simply pte trick isn't enough, because we need:
>>>>> - drop all writes silently
>>>>> - all reads return 0xff
>>>>>
>>>>> ptes can't do that themselves, we minimally need write protection and then
>>>>> silently proceed on each write fault without restarting the instruction.
>>>>> Better would be to only catch reads, but x86 doesn't do write-only pte
>>>>> permissions afaik.
>>>> You are not thinking far enough :)
>>>>
>>>> The dummy PTE is point to a dummy MMIO page which is just never used.
>>>>
>>>> That hast the exact same properties than our removed MMIO space just doesn't
>>>> goes bananas when a new device is MMIO mapped into that and our driver still
>>>> tries to write there.
>>> Hm, but where do we get such a "guaranteed never used" mmio page from?
>> Well we have tons of unused IO space on 64bit systems these days.
>>
>> Doesn't really needs to be PCIe address space, doesn't it?
> That sounds very trusting to modern systems not decoding random
> ranges. E.g. the pci code stopped extending the host bridge windows on
> its own, entirely relying on the acpi provided ranges, to avoid
> stomping on stuff that's the but not listed anywhere.
>
> I guess if we have a range behind a pci bridge, which isn't used by
> any device, but decoded by the bridge, then that should be safe
> enough. Maybe could even have an option in upstream to do that on
> unplug, if a certain flag is set, or a cmdline option.
> -Daniel


Question - Why can't we just set those PTEs to point to system memory (another 
RO dummy page)
filled with 1s ?

Andrey


>
>> Christian.
>>
>>> It's a nifty idea indeed otherwise ...
>>> -Daniel
>>>
>>>> Regards,
>>>> Christian.
>>>>
>>>>
>>>>>>>>> But ugh ...
>>>>>>>>>
>>>>>>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>>>>>>> against 0xff reads is practically impossible. So maybe you need to add
>>>>>>>>> this as one of the tasks here?
>>>>>>>> Or I could just for validation purposes return ~0 from all reg reads in the code
>>>>>>>> and ignore writes if drm_dev_unplugged, this could already easily validate a big
>>>>>>>> portion of the code flow under such scenario.
>>>>>>> Hm yeah if your really wrap them all, that should work too. Since
>>>>>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>>>>>> warning free, should be doable to guarantee this.
>>>>>> Problem is that ~0 is not always a valid register value.
>>>>>>
>>>>>> You would need to audit every register read that it doesn't use the returned
>>>>>> value blindly as index or similar. That is quite a bit of work.
>>>>> Yeah that's the entire crux here :-/
>>>>> -Daniel
>
Christian König Feb. 9, 2021, 7:58 a.m. UTC | #27
Am 08.02.21 um 23:15 schrieb Andrey Grodzovsky:
>
> On 2/8/21 11:23 AM, Daniel Vetter wrote:
>> On Mon, Feb 8, 2021 at 3:00 PM Christian König 
>> <christian.koenig@amd.com> wrote:
>>> Am 08.02.21 um 11:11 schrieb Daniel Vetter:
>>>> On Mon, Feb 08, 2021 at 11:03:15AM +0100, Christian König wrote:
>>>>> Am 08.02.21 um 10:48 schrieb Daniel Vetter:
>>>>>> On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
>>>>>>> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
>>>>>>>> [SNIP]
>>>>>>>>> Clarification - as far as I know there are no page fault 
>>>>>>>>> handlers for kernel
>>>>>>>>> mappings. And we are talking about kernel mappings here, right 
>>>>>>>>> ?  If there were
>>>>>>>>> I could solve all those issues the same as I do for user 
>>>>>>>>> mappings, by
>>>>>>>>> invalidating all existing mappings in the kernel (both kmaps 
>>>>>>>>> and ioreamps)and
>>>>>>>>> insert dummy zero or ~0 filled page instead.
>>>>>>>>> Also, I assume forcefully remapping the IO BAR to ~0 filled 
>>>>>>>>> page would involve
>>>>>>>>> ioremap API and it's not something that I think can be easily 
>>>>>>>>> done according to
>>>>>>>>> am answer i got to a related topic a few weeks ago
>>>>>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C9d1bdf4cee504cd71b4908d8cc4df310%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483982454608249%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=Anw%2BOwJ%2B5tvjW3tmkVNdz13%2BZ18vdpfOLWqsUZL7D2I%3D&amp;reserved=0 
>>>>>>>>> (that was the only reply
>>>>>>>>> i got)
>>>>>>>> mmiotrace can, but only for debug, and only on x86 platforms:
>>>>>>>>
>>>>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C9d1bdf4cee504cd71b4908d8cc4df310%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483982454608249%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=Wa7BFNySVQJLyD6WY4pZHTP1QfeZwD7F5ydBrXuxppQ%3D&amp;reserved=0 
>>>>>>>>
>>>>>>>>
>>>>>>>> Should be feasible (but maybe not worth the effort) to extend 
>>>>>>>> this to
>>>>>>>> support fake unplug.
>>>>>>> Mhm, interesting idea you guys brought up here.
>>>>>>>
>>>>>>> We don't need a page fault for this to work, all we need to do 
>>>>>>> is to insert
>>>>>>> dummy PTEs into the kernels page table at the place where 
>>>>>>> previously the
>>>>>>> MMIO mapping has been.
>>>>>> Simply pte trick isn't enough, because we need:
>>>>>> - drop all writes silently
>>>>>> - all reads return 0xff
>>>>>>
>>>>>> ptes can't do that themselves, we minimally need write protection 
>>>>>> and then
>>>>>> silently proceed on each write fault without restarting the 
>>>>>> instruction.
>>>>>> Better would be to only catch reads, but x86 doesn't do 
>>>>>> write-only pte
>>>>>> permissions afaik.
>>>>> You are not thinking far enough :)
>>>>>
>>>>> The dummy PTE is point to a dummy MMIO page which is just never used.
>>>>>
>>>>> That hast the exact same properties than our removed MMIO space 
>>>>> just doesn't
>>>>> goes bananas when a new device is MMIO mapped into that and our 
>>>>> driver still
>>>>> tries to write there.
>>>> Hm, but where do we get such a "guaranteed never used" mmio page from?
>>> Well we have tons of unused IO space on 64bit systems these days.
>>>
>>> Doesn't really needs to be PCIe address space, doesn't it?
>> That sounds very trusting to modern systems not decoding random
>> ranges. E.g. the pci code stopped extending the host bridge windows on
>> its own, entirely relying on the acpi provided ranges, to avoid
>> stomping on stuff that's the but not listed anywhere.
>>
>> I guess if we have a range behind a pci bridge, which isn't used by
>> any device, but decoded by the bridge, then that should be safe
>> enough. Maybe could even have an option in upstream to do that on
>> unplug, if a certain flag is set, or a cmdline option.
>> -Daniel
>
>
> Question - Why can't we just set those PTEs to point to system memory 
> (another RO dummy page)
> filled with 1s ?


Then writes are not discarded. E.g. the 1s would change to something else.

Christian.


>
> Andrey
>
>
>>
>>> Christian.
>>>
>>>> It's a nifty idea indeed otherwise ...
>>>> -Daniel
>>>>
>>>>> Regards,
>>>>> Christian.
>>>>>
>>>>>
>>>>>>>>>> But ugh ...
>>>>>>>>>>
>>>>>>>>>> Otoh validating an entire driver like amdgpu without such a 
>>>>>>>>>> trick
>>>>>>>>>> against 0xff reads is practically impossible. So maybe you 
>>>>>>>>>> need to add
>>>>>>>>>> this as one of the tasks here?
>>>>>>>>> Or I could just for validation purposes return ~0 from all reg 
>>>>>>>>> reads in the code
>>>>>>>>> and ignore writes if drm_dev_unplugged, this could already 
>>>>>>>>> easily validate a big
>>>>>>>>> portion of the code flow under such scenario.
>>>>>>>> Hm yeah if your really wrap them all, that should work too. Since
>>>>>>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>>>>>>> warning free, should be doable to guarantee this.
>>>>>>> Problem is that ~0 is not always a valid register value.
>>>>>>>
>>>>>>> You would need to audit every register read that it doesn't use 
>>>>>>> the returned
>>>>>>> value blindly as index or similar. That is quite a bit of work.
>>>>>> Yeah that's the entire crux here :-/
>>>>>> -Daniel
>>
Christian König Feb. 9, 2021, 8:27 a.m. UTC | #28
Am 08.02.21 um 23:09 schrieb Andrey Grodzovsky:
>
>
> On 2/8/21 4:37 AM, Christian König wrote:
>> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
>>> [SNIP]
>>>> Clarification - as far as I know there are no page fault handlers 
>>>> for kernel
>>>> mappings. And we are talking about kernel mappings here, right ?  
>>>> If there were
>>>> I could solve all those issues the same as I do for user mappings, by
>>>> invalidating all existing mappings in the kernel (both kmaps and 
>>>> ioreamps)and
>>>> insert dummy zero or ~0 filled page instead.
>>>> Also, I assume forcefully remapping the IO BAR to ~0 filled page 
>>>> would involve
>>>> ioremap API and it's not something that I think can be easily done 
>>>> according to
>>>> am answer i got to a related topic a few weeks ago
>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cb159d3ce264944486c8008d8cc15233a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483738446813868%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=6eP0nhS%2BZwp1Y54CwfX8vaV3FTWbW8IylW5JFaf92pY%3D&amp;reserved=0 
>>>> (that was the only reply
>>>> i got)
>>> mmiotrace can, but only for debug, and only on x86 platforms:
>>>
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cb159d3ce264944486c8008d8cc15233a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483738446813868%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=QBF9J%2BVIRUkUTTjvNoZR8NqFNt8CpHkcknH2qKX7dd8%3D&amp;reserved=0 
>>>
>>>
>>> Should be feasible (but maybe not worth the effort) to extend this to
>>> support fake unplug.
>>
>> Mhm, interesting idea you guys brought up here.
>>
>> We don't need a page fault for this to work, all we need to do is to 
>> insert dummy PTEs into the kernels page table at the place where 
>> previously the MMIO mapping has been.
>
>
> But that exactly what Mathew from linux-mm says is not a trivial thing 
> to do, quote:
>
> "
>
> ioremap() is done through the vmalloc space.  It would, in theory, be
> possible to reprogram the page tables used for vmalloc to point to your
> magic page.  I don't think we have such a mechanism today, and there are
> lots of problems with things like TLB flushes.  It's probably going to
> be harder than you think.
> "

I haven't followed the full discussion, but I don't see much preventing 
this.

All you need is a new ioremap_dummy() function which takes the old start 
and length of the mapping.

Still a bit core and maybe even platform code, but rather useful I think.

Christian.

>
> If you believe it's actually doable then it would be useful not only for simulating device
> unplugged situation with all MMIOs returning 0xff... but for actual handling of driver accesses
> to MMIO after device is gone and, we could then drop entirely this patch as there would be no need
> to guard against such accesses post device unplug.


>
>   
>>
>>>>> But ugh ...
>>>>>
>>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>>> against 0xff reads is practically impossible. So maybe you need to 
>>>>> add
>>>>> this as one of the tasks here?
>>>> Or I could just for validation purposes return ~0 from all reg 
>>>> reads in the code
>>>> and ignore writes if drm_dev_unplugged, this could already easily 
>>>> validate a big
>>>> portion of the code flow under such scenario.
>>> Hm yeah if your really wrap them all, that should work too. Since
>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>> warning free, should be doable to guarantee this.
>>
>> Problem is that ~0 is not always a valid register value.
>>
>> You would need to audit every register read that it doesn't use the 
>> returned value blindly as index or similar. That is quite a bit of work.
>
>
> But ~0 is the value that will be returned for every read post device 
> unplug, regardless if it's valid or not, and we have to cope with
> it then, no ?
>
> Andrey
>
>
>>
>> Regards,
>> Christian.
>>
>>> -Daniel
>>>
>>>> Andrey
>>>>
>>
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Daniel Vetter Feb. 9, 2021, 9:46 a.m. UTC | #29
On Tue, Feb 09, 2021 at 09:27:03AM +0100, Christian König wrote:
> 
> 
> Am 08.02.21 um 23:09 schrieb Andrey Grodzovsky:
> > 
> > 
> > On 2/8/21 4:37 AM, Christian König wrote:
> > > Am 07.02.21 um 22:50 schrieb Daniel Vetter:
> > > > [SNIP]
> > > > > Clarification - as far as I know there are no page fault
> > > > > handlers for kernel
> > > > > mappings. And we are talking about kernel mappings here,
> > > > > right ?  If there were
> > > > > I could solve all those issues the same as I do for user mappings, by
> > > > > invalidating all existing mappings in the kernel (both kmaps
> > > > > and ioreamps)and
> > > > > insert dummy zero or ~0 filled page instead.
> > > > > Also, I assume forcefully remapping the IO BAR to ~0 filled
> > > > > page would involve
> > > > > ioremap API and it's not something that I think can be
> > > > > easily done according to
> > > > > am answer i got to a related topic a few weeks ago
> > > > > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cb159d3ce264944486c8008d8cc15233a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483738446813868%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=6eP0nhS%2BZwp1Y54CwfX8vaV3FTWbW8IylW5JFaf92pY%3D&amp;reserved=0
> > > > > (that was the only reply
> > > > > i got)
> > > > mmiotrace can, but only for debug, and only on x86 platforms:
> > > > 
> > > > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7Cb159d3ce264944486c8008d8cc15233a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483738446813868%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=QBF9J%2BVIRUkUTTjvNoZR8NqFNt8CpHkcknH2qKX7dd8%3D&amp;reserved=0
> > > > 
> > > > 
> > > > Should be feasible (but maybe not worth the effort) to extend this to
> > > > support fake unplug.
> > > 
> > > Mhm, interesting idea you guys brought up here.
> > > 
> > > We don't need a page fault for this to work, all we need to do is to
> > > insert dummy PTEs into the kernels page table at the place where
> > > previously the MMIO mapping has been.
> > 
> > 
> > But that exactly what Mathew from linux-mm says is not a trivial thing
> > to do, quote:
> > 
> > "
> > 
> > ioremap() is done through the vmalloc space.  It would, in theory, be
> > possible to reprogram the page tables used for vmalloc to point to your
> > magic page.  I don't think we have such a mechanism today, and there are
> > lots of problems with things like TLB flushes.  It's probably going to
> > be harder than you think.
> > "
> 
> I haven't followed the full discussion, but I don't see much preventing
> this.
> 
> All you need is a new ioremap_dummy() function which takes the old start and
> length of the mapping.
> 
> Still a bit core and maybe even platform code, but rather useful I think.

Yeah we don't care about races, so if the tlb flushing isn't perfect
that's fine.

Also if we glue this into the mmiotrace infrastructure, that already has
all the fault handling. So on x86 I think we could even make it perfect
(but that feels like overkill) and fully atomic. Plus the mmiotrace
overhead (even if we don't capture anything) is probably a bit much even
for testing in CI or somewhere like that.
-Daniel

> 
> Christian.
> 
> > 
> > If you believe it's actually doable then it would be useful not only for simulating device
> > unplugged situation with all MMIOs returning 0xff... but for actual handling of driver accesses
> > to MMIO after device is gone and, we could then drop entirely this patch as there would be no need
> > to guard against such accesses post device unplug.
> 
> 
> > 
> > > 
> > > > > > But ugh ...
> > > > > > 
> > > > > > Otoh validating an entire driver like amdgpu without such a trick
> > > > > > against 0xff reads is practically impossible. So maybe
> > > > > > you need to add
> > > > > > this as one of the tasks here?
> > > > > Or I could just for validation purposes return ~0 from all
> > > > > reg reads in the code
> > > > > and ignore writes if drm_dev_unplugged, this could already
> > > > > easily validate a big
> > > > > portion of the code flow under such scenario.
> > > > Hm yeah if your really wrap them all, that should work too. Since
> > > > iommappings have __iomem pointer type, as long as amdgpu is sparse
> > > > warning free, should be doable to guarantee this.
> > > 
> > > Problem is that ~0 is not always a valid register value.
> > > 
> > > You would need to audit every register read that it doesn't use the
> > > returned value blindly as index or similar. That is quite a bit of
> > > work.
> > 
> > 
> > But ~0 is the value that will be returned for every read post device
> > unplug, regardless if it's valid or not, and we have to cope with
> > it then, no ?
> > 
> > Andrey
> > 
> > 
> > > 
> > > Regards,
> > > Christian.
> > > 
> > > > -Daniel
> > > > 
> > > > > Andrey
> > > > > 
> > > 
> > 
> > _______________________________________________
> > amd-gfx mailing list
> > amd-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/amd-gfx
>
Andrey Grodzovsky Feb. 9, 2021, 2:30 p.m. UTC | #30
On 2/9/21 2:58 AM, Christian König wrote:
>
> Am 08.02.21 um 23:15 schrieb Andrey Grodzovsky:
>>
>> On 2/8/21 11:23 AM, Daniel Vetter wrote:
>>> On Mon, Feb 8, 2021 at 3:00 PM Christian König <christian.koenig@amd.com> 
>>> wrote:
>>>> Am 08.02.21 um 11:11 schrieb Daniel Vetter:
>>>>> On Mon, Feb 08, 2021 at 11:03:15AM +0100, Christian König wrote:
>>>>>> Am 08.02.21 um 10:48 schrieb Daniel Vetter:
>>>>>>> On Mon, Feb 08, 2021 at 10:37:19AM +0100, Christian König wrote:
>>>>>>>> Am 07.02.21 um 22:50 schrieb Daniel Vetter:
>>>>>>>>> [SNIP]
>>>>>>>>>> Clarification - as far as I know there are no page fault handlers for 
>>>>>>>>>> kernel
>>>>>>>>>> mappings. And we are talking about kernel mappings here, right ?  If 
>>>>>>>>>> there were
>>>>>>>>>> I could solve all those issues the same as I do for user mappings, by
>>>>>>>>>> invalidating all existing mappings in the kernel (both kmaps and 
>>>>>>>>>> ioreamps)and
>>>>>>>>>> insert dummy zero or ~0 filled page instead.
>>>>>>>>>> Also, I assume forcefully remapping the IO BAR to ~0 filled page 
>>>>>>>>>> would involve
>>>>>>>>>> ioremap API and it's not something that I think can be easily done 
>>>>>>>>>> according to
>>>>>>>>>> am answer i got to a related topic a few weeks ago
>>>>>>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.spinics.net%2Flists%2Flinux-pci%2Fmsg103396.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C9d1bdf4cee504cd71b4908d8cc4df310%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483982454608249%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=Anw%2BOwJ%2B5tvjW3tmkVNdz13%2BZ18vdpfOLWqsUZL7D2I%3D&amp;reserved=0 
>>>>>>>>>> (that was the only reply
>>>>>>>>>> i got)
>>>>>>>>> mmiotrace can, but only for debug, and only on x86 platforms:
>>>>>>>>>
>>>>>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Ftrace%2Fmmiotrace.html&amp;data=04%7C01%7CAndrey.Grodzovsky%40amd.com%7C9d1bdf4cee504cd71b4908d8cc4df310%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483982454608249%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=Wa7BFNySVQJLyD6WY4pZHTP1QfeZwD7F5ydBrXuxppQ%3D&amp;reserved=0 
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Should be feasible (but maybe not worth the effort) to extend this to
>>>>>>>>> support fake unplug.
>>>>>>>> Mhm, interesting idea you guys brought up here.
>>>>>>>>
>>>>>>>> We don't need a page fault for this to work, all we need to do is to 
>>>>>>>> insert
>>>>>>>> dummy PTEs into the kernels page table at the place where previously the
>>>>>>>> MMIO mapping has been.
>>>>>>> Simply pte trick isn't enough, because we need:
>>>>>>> - drop all writes silently
>>>>>>> - all reads return 0xff
>>>>>>>
>>>>>>> ptes can't do that themselves, we minimally need write protection and then
>>>>>>> silently proceed on each write fault without restarting the instruction.
>>>>>>> Better would be to only catch reads, but x86 doesn't do write-only pte
>>>>>>> permissions afaik.
>>>>>> You are not thinking far enough :)
>>>>>>
>>>>>> The dummy PTE is point to a dummy MMIO page which is just never used.
>>>>>>
>>>>>> That hast the exact same properties than our removed MMIO space just doesn't
>>>>>> goes bananas when a new device is MMIO mapped into that and our driver still
>>>>>> tries to write there.
>>>>> Hm, but where do we get such a "guaranteed never used" mmio page from?
>>>> Well we have tons of unused IO space on 64bit systems these days.
>>>>
>>>> Doesn't really needs to be PCIe address space, doesn't it?
>>> That sounds very trusting to modern systems not decoding random
>>> ranges. E.g. the pci code stopped extending the host bridge windows on
>>> its own, entirely relying on the acpi provided ranges, to avoid
>>> stomping on stuff that's the but not listed anywhere.
>>>
>>> I guess if we have a range behind a pci bridge, which isn't used by
>>> any device, but decoded by the bridge, then that should be safe
>>> enough. Maybe could even have an option in upstream to do that on
>>> unplug, if a certain flag is set, or a cmdline option.
>>> -Daniel
>>
>>
>> Question - Why can't we just set those PTEs to point to system memory 
>> (another RO dummy page)
>> filled with 1s ?
>
>
> Then writes are not discarded. E.g. the 1s would change to something else.
>
> Christian.


I see but, what about marking the mappings as RO and discarding the write access 
page faults continuously until the device is finalized ?
Regarding using an unused range behind the upper bridge as Daniel suggested, I 
wonder will this interfere with
the upcoming feature to support BARs movement  during hot plug - 
https://www.spinics.net/lists/linux-pci/msg103195.html ?

Andrey


>
>
>>
>> Andrey
>>
>>
>>>
>>>> Christian.
>>>>
>>>>> It's a nifty idea indeed otherwise ...
>>>>> -Daniel
>>>>>
>>>>>> Regards,
>>>>>> Christian.
>>>>>>
>>>>>>
>>>>>>>>>>> But ugh ...
>>>>>>>>>>>
>>>>>>>>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>>>>>>>>> against 0xff reads is practically impossible. So maybe you need to add
>>>>>>>>>>> this as one of the tasks here?
>>>>>>>>>> Or I could just for validation purposes return ~0 from all reg reads 
>>>>>>>>>> in the code
>>>>>>>>>> and ignore writes if drm_dev_unplugged, this could already easily 
>>>>>>>>>> validate a big
>>>>>>>>>> portion of the code flow under such scenario.
>>>>>>>>> Hm yeah if your really wrap them all, that should work too. Since
>>>>>>>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>>>>>>>> warning free, should be doable to guarantee this.
>>>>>>>> Problem is that ~0 is not always a valid register value.
>>>>>>>>
>>>>>>>> You would need to audit every register read that it doesn't use the 
>>>>>>>> returned
>>>>>>>> value blindly as index or similar. That is quite a bit of work.
>>>>>>> Yeah that's the entire crux here :-/
>>>>>>> -Daniel
>>>
Christian König Feb. 9, 2021, 3:40 p.m. UTC | #31
Am 09.02.21 um 15:30 schrieb Andrey Grodzovsky:
> [SNIP]
>>> Question - Why can't we just set those PTEs to point to system 
>>> memory (another RO dummy page)
>>> filled with 1s ?
>>
>>
>> Then writes are not discarded. E.g. the 1s would change to something 
>> else.
>>
>> Christian.
>
>
> I see but, what about marking the mappings as RO and discarding the 
> write access page faults continuously until the device is finalized ?
> Regarding using an unused range behind the upper bridge as Daniel 
> suggested, I wonder will this interfere with
> the upcoming feature to support BARs movement  during hot plug - 
> https://www.spinics.net/lists/linux-pci/msg103195.html ?

In the picture in my head the address will never be used.

But it doesn't even needs to be an unused range of the root bridge. That 
one is usually stuffed full by the BIOS.

For my BAR resize work I looked at quite a bunch of NB documentation. At 
least for AMD CPUs we should always have an MMIO address which is never 
ever used. That makes this platform/CPU dependent, but the code is just 
minimal.

The really really nice thing about this approach is that you could unit 
test and audit the code for problems even without *real* hotplug 
hardware. E.g. we can swap the kernel PTEs and see how the whole power 
and display code reacts to that etc....

Christian.

>
> Andrey
>
>
>>
>>
>>>
>>> Andrey
>>>
>>>
>>>>
>>>>> Christian.
>>>>>
>>>>>> It's a nifty idea indeed otherwise ...
>>>>>> -Daniel
>>>>>>
>>>>>>> Regards,
>>>>>>> Christian.
>>>>>>>
>>>>>>>
>>>>>>>>>>>> But ugh ...
>>>>>>>>>>>>
>>>>>>>>>>>> Otoh validating an entire driver like amdgpu without such a 
>>>>>>>>>>>> trick
>>>>>>>>>>>> against 0xff reads is practically impossible. So maybe you 
>>>>>>>>>>>> need to add
>>>>>>>>>>>> this as one of the tasks here?
>>>>>>>>>>> Or I could just for validation purposes return ~0 from all 
>>>>>>>>>>> reg reads in the code
>>>>>>>>>>> and ignore writes if drm_dev_unplugged, this could already 
>>>>>>>>>>> easily validate a big
>>>>>>>>>>> portion of the code flow under such scenario.
>>>>>>>>>> Hm yeah if your really wrap them all, that should work too. 
>>>>>>>>>> Since
>>>>>>>>>> iommappings have __iomem pointer type, as long as amdgpu is 
>>>>>>>>>> sparse
>>>>>>>>>> warning free, should be doable to guarantee this.
>>>>>>>>> Problem is that ~0 is not always a valid register value.
>>>>>>>>>
>>>>>>>>> You would need to audit every register read that it doesn't 
>>>>>>>>> use the returned
>>>>>>>>> value blindly as index or similar. That is quite a bit of work.
>>>>>>>> Yeah that's the entire crux here :-/
>>>>>>>> -Daniel
>>>>
Andrey Grodzovsky Feb. 10, 2021, 10:01 p.m. UTC | #32
On 2/9/21 10:40 AM, Christian König wrote:
> Am 09.02.21 um 15:30 schrieb Andrey Grodzovsky:
>> [SNIP]
>>>> Question - Why can't we just set those PTEs to point to system memory 
>>>> (another RO dummy page)
>>>> filled with 1s ?
>>>
>>>
>>> Then writes are not discarded. E.g. the 1s would change to something else.
>>>
>>> Christian.
>>
>>
>> I see but, what about marking the mappings as RO and discarding the write 
>> access page faults continuously until the device is finalized ?
>> Regarding using an unused range behind the upper bridge as Daniel suggested, 
>> I wonder will this interfere with
>> the upcoming feature to support BARs movement  during hot plug - 
>> https://www.spinics.net/lists/linux-pci/msg103195.html ?
>
> In the picture in my head the address will never be used.
>
> But it doesn't even needs to be an unused range of the root bridge. That one 
> is usually stuffed full by the BIOS.
>
> For my BAR resize work I looked at quite a bunch of NB documentation. At least 
> for AMD CPUs we should always have an MMIO address which is never ever used. 
> That makes this platform/CPU dependent, but the code is just minimal.
>
> The really really nice thing about this approach is that you could unit test 
> and audit the code for problems even without *real* hotplug hardware. E.g. we 
> can swap the kernel PTEs and see how the whole power and display code reacts 
> to that etc....
>
> Christian.


Tried to play with hacking mmio tracer as Daniel suggested but just hanged the 
machine so...

Can you tell me how to dynamically obtain this kind of unused MMIO address ? I 
think given such address, writing
to which is dropped and reading from return all 1s, I can then do something like 
bellow, if that what u meant -

for (address = adev->rmmio; address < adev->rmmio_size; adress += PAGE_SIZE) {

     old_pte = get_locked_pte(init_mm, address)
     dummy_pte = pfn_pte(fake_mmio_address, 0);
     set_pte(&old_pte, dummy_pte)

}

flush_tlb ???

P.S I hope to obtain thunderbolt eGPU adapter soon so even if this won't work I 
still will be able to test how the driver handles all 1s.

Andrey

>
>>
>> Andrey
>>
>>
>>>
>>>
>>>>
>>>> Andrey
>>>>
>>>>
>>>>>
>>>>>> Christian.
>>>>>>
>>>>>>> It's a nifty idea indeed otherwise ...
>>>>>>> -Daniel
>>>>>>>
>>>>>>>> Regards,
>>>>>>>> Christian.
>>>>>>>>
>>>>>>>>
>>>>>>>>>>>>> But ugh ...
>>>>>>>>>>>>>
>>>>>>>>>>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>>>>>>>>>>> against 0xff reads is practically impossible. So maybe you need to 
>>>>>>>>>>>>> add
>>>>>>>>>>>>> this as one of the tasks here?
>>>>>>>>>>>> Or I could just for validation purposes return ~0 from all reg 
>>>>>>>>>>>> reads in the code
>>>>>>>>>>>> and ignore writes if drm_dev_unplugged, this could already easily 
>>>>>>>>>>>> validate a big
>>>>>>>>>>>> portion of the code flow under such scenario.
>>>>>>>>>>> Hm yeah if your really wrap them all, that should work too. Since
>>>>>>>>>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>>>>>>>>>> warning free, should be doable to guarantee this.
>>>>>>>>>> Problem is that ~0 is not always a valid register value.
>>>>>>>>>>
>>>>>>>>>> You would need to audit every register read that it doesn't use the 
>>>>>>>>>> returned
>>>>>>>>>> value blindly as index or similar. That is quite a bit of work.
>>>>>>>>> Yeah that's the entire crux here :-/
>>>>>>>>> -Daniel
>>>>>
>
Andrey Grodzovsky Feb. 12, 2021, 3 p.m. UTC | #33
Ping

Andrey

On 2/10/21 5:01 PM, Andrey Grodzovsky wrote:
>
> On 2/9/21 10:40 AM, Christian König wrote:
>> Am 09.02.21 um 15:30 schrieb Andrey Grodzovsky:
>>> [SNIP]
>>>>> Question - Why can't we just set those PTEs to point to system memory 
>>>>> (another RO dummy page)
>>>>> filled with 1s ?
>>>>
>>>>
>>>> Then writes are not discarded. E.g. the 1s would change to something else.
>>>>
>>>> Christian.
>>>
>>>
>>> I see but, what about marking the mappings as RO and discarding the write 
>>> access page faults continuously until the device is finalized ?
>>> Regarding using an unused range behind the upper bridge as Daniel suggested, 
>>> I wonder will this interfere with
>>> the upcoming feature to support BARs movement  during hot plug - 
>>> https://www.spinics.net/lists/linux-pci/msg103195.html ?
>>
>> In the picture in my head the address will never be used.
>>
>> But it doesn't even needs to be an unused range of the root bridge. That one 
>> is usually stuffed full by the BIOS.
>>
>> For my BAR resize work I looked at quite a bunch of NB documentation. At 
>> least for AMD CPUs we should always have an MMIO address which is never ever 
>> used. That makes this platform/CPU dependent, but the code is just minimal.
>>
>> The really really nice thing about this approach is that you could unit test 
>> and audit the code for problems even without *real* hotplug hardware. E.g. we 
>> can swap the kernel PTEs and see how the whole power and display code reacts 
>> to that etc....
>>
>> Christian.
>
>
> Tried to play with hacking mmio tracer as Daniel suggested but just hanged the 
> machine so...
>
> Can you tell me how to dynamically obtain this kind of unused MMIO address ? I 
> think given such address, writing
> to which is dropped and reading from return all 1s, I can then do something 
> like bellow, if that what u meant -
>
> for (address = adev->rmmio; address < adev->rmmio_size; adress += PAGE_SIZE) {
>
>     old_pte = get_locked_pte(init_mm, address)
>     dummy_pte = pfn_pte(fake_mmio_address, 0);
>     set_pte(&old_pte, dummy_pte)
>
> }
>
> flush_tlb ???
>
> P.S I hope to obtain thunderbolt eGPU adapter soon so even if this won't work 
> I still will be able to test how the driver handles all 1s.
>
> Andrey
>
>>
>>>
>>> Andrey
>>>
>>>
>>>>
>>>>
>>>>>
>>>>> Andrey
>>>>>
>>>>>
>>>>>>
>>>>>>> Christian.
>>>>>>>
>>>>>>>> It's a nifty idea indeed otherwise ...
>>>>>>>> -Daniel
>>>>>>>>
>>>>>>>>> Regards,
>>>>>>>>> Christian.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>>>>>> But ugh ...
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Otoh validating an entire driver like amdgpu without such a trick
>>>>>>>>>>>>>> against 0xff reads is practically impossible. So maybe you need 
>>>>>>>>>>>>>> to add
>>>>>>>>>>>>>> this as one of the tasks here?
>>>>>>>>>>>>> Or I could just for validation purposes return ~0 from all reg 
>>>>>>>>>>>>> reads in the code
>>>>>>>>>>>>> and ignore writes if drm_dev_unplugged, this could already easily 
>>>>>>>>>>>>> validate a big
>>>>>>>>>>>>> portion of the code flow under such scenario.
>>>>>>>>>>>> Hm yeah if your really wrap them all, that should work too. Since
>>>>>>>>>>>> iommappings have __iomem pointer type, as long as amdgpu is sparse
>>>>>>>>>>>> warning free, should be doable to guarantee this.
>>>>>>>>>>> Problem is that ~0 is not always a valid register value.
>>>>>>>>>>>
>>>>>>>>>>> You would need to audit every register read that it doesn't use the 
>>>>>>>>>>> returned
>>>>>>>>>>> value blindly as index or similar. That is quite a bit of work.
>>>>>>>>>> Yeah that's the entire crux here :-/
>>>>>>>>>> -Daniel
>>>>>>
>>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index e99f4f1..0a9d73c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -72,6 +72,8 @@ 
 
 #include <linux/iommu.h>
 
+#include <drm/drm_drv.h>
+
 MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
@@ -404,13 +406,21 @@  uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset)
  */
 void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value)
 {
+	int idx;
+
 	if (adev->in_pci_err_recovery)
 		return;
 
+
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
+
 	if (offset < adev->rmmio_size)
 		writeb(value, adev->rmmio + offset);
 	else
 		BUG();
+
+	drm_dev_exit(idx);
 }
 
 /**
@@ -427,9 +437,14 @@  void amdgpu_device_wreg(struct amdgpu_device *adev,
 			uint32_t reg, uint32_t v,
 			uint32_t acc_flags)
 {
+	int idx;
+
 	if (adev->in_pci_err_recovery)
 		return;
 
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
+
 	if ((reg * 4) < adev->rmmio_size) {
 		if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
 		    amdgpu_sriov_runtime(adev) &&
@@ -444,6 +459,8 @@  void amdgpu_device_wreg(struct amdgpu_device *adev,
 	}
 
 	trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
+
+	drm_dev_exit(idx);
 }
 
 /*
@@ -454,9 +471,14 @@  void amdgpu_device_wreg(struct amdgpu_device *adev,
 void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
 			     uint32_t reg, uint32_t v)
 {
+	int idx;
+
 	if (adev->in_pci_err_recovery)
 		return;
 
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
+
 	if (amdgpu_sriov_fullaccess(adev) &&
 	    adev->gfx.rlc.funcs &&
 	    adev->gfx.rlc.funcs->is_rlcg_access_range) {
@@ -465,6 +487,8 @@  void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
 	} else {
 		writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
 	}
+
+	drm_dev_exit(idx);
 }
 
 /**
@@ -499,15 +523,22 @@  u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg)
  */
 void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
 {
+	int idx;
+
 	if (adev->in_pci_err_recovery)
 		return;
 
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
+
 	if ((reg * 4) < adev->rio_mem_size)
 		iowrite32(v, adev->rio_mem + (reg * 4));
 	else {
 		iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
 		iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
 	}
+
+	drm_dev_exit(idx);
 }
 
 /**
@@ -544,14 +575,21 @@  u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index)
  */
 void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
 {
+	int idx;
+
 	if (adev->in_pci_err_recovery)
 		return;
 
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
+
 	if (index < adev->doorbell.num_doorbells) {
 		writel(v, adev->doorbell.ptr + index);
 	} else {
 		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
 	}
+
+	drm_dev_exit(idx);
 }
 
 /**
@@ -588,14 +626,21 @@  u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index)
  */
 void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
 {
+	int idx;
+
 	if (adev->in_pci_err_recovery)
 		return;
 
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
+
 	if (index < adev->doorbell.num_doorbells) {
 		atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
 	} else {
 		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
 	}
+
+	drm_dev_exit(idx);
 }
 
 /**
@@ -682,6 +727,10 @@  void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
 	unsigned long flags;
 	void __iomem *pcie_index_offset;
 	void __iomem *pcie_data_offset;
+	int idx;
+
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
 
 	spin_lock_irqsave(&adev->pcie_idx_lock, flags);
 	pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
@@ -692,6 +741,8 @@  void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
 	writel(reg_data, pcie_data_offset);
 	readl(pcie_data_offset);
 	spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+
+	drm_dev_exit(idx);
 }
 
 /**
@@ -711,6 +762,10 @@  void amdgpu_device_indirect_wreg64(struct amdgpu_device *adev,
 	unsigned long flags;
 	void __iomem *pcie_index_offset;
 	void __iomem *pcie_data_offset;
+	int idx;
+
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return;
 
 	spin_lock_irqsave(&adev->pcie_idx_lock, flags);
 	pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
@@ -727,6 +782,8 @@  void amdgpu_device_indirect_wreg64(struct amdgpu_device *adev,
 	writel((u32)(reg_data >> 32), pcie_data_offset);
 	readl(pcie_data_offset);
 	spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+
+	drm_dev_exit(idx);
 }
 
 /**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index fe1a39f..1beb4e6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -31,6 +31,8 @@ 
 #include "amdgpu_ras.h"
 #include "amdgpu_xgmi.h"
 
+#include <drm/drm_drv.h>
+
 /**
  * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
  *
@@ -98,6 +100,10 @@  int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
 {
 	void __iomem *ptr = (void *)cpu_pt_addr;
 	uint64_t value;
+	int idx;
+
+	if (!drm_dev_enter(&adev->ddev, &idx))
+		return 0;
 
 	/*
 	 * The following is for PTE only. GART does not have PDEs.
@@ -105,6 +111,9 @@  int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
 	value = addr & 0x0000FFFFFFFFF000ULL;
 	value |= flags;
 	writeq(value, ptr + (gpu_page_idx * 8));
+
+	drm_dev_exit(idx);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 523d22d..89e2bfe 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -37,6 +37,8 @@ 
 
 #include "amdgpu_ras.h"
 
+#include <drm/drm_drv.h>
+
 static int psp_sysfs_init(struct amdgpu_device *adev);
 static void psp_sysfs_fini(struct amdgpu_device *adev);
 
@@ -248,7 +250,7 @@  psp_cmd_submit_buf(struct psp_context *psp,
 		   struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
 {
 	int ret;
-	int index;
+	int index, idx;
 	int timeout = 2000;
 	bool ras_intr = false;
 	bool skip_unsupport = false;
@@ -256,6 +258,9 @@  psp_cmd_submit_buf(struct psp_context *psp,
 	if (psp->adev->in_pci_err_recovery)
 		return 0;
 
+	if (!drm_dev_enter(&psp->adev->ddev, &idx))
+		return 0;
+
 	mutex_lock(&psp->mutex);
 
 	memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
@@ -266,8 +271,7 @@  psp_cmd_submit_buf(struct psp_context *psp,
 	ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index);
 	if (ret) {
 		atomic_dec(&psp->fence_value);
-		mutex_unlock(&psp->mutex);
-		return ret;
+		goto exit;
 	}
 
 	amdgpu_asic_invalidate_hdp(psp->adev, NULL);
@@ -307,8 +311,8 @@  psp_cmd_submit_buf(struct psp_context *psp,
 			 psp->cmd_buf_mem->cmd_id,
 			 psp->cmd_buf_mem->resp.status);
 		if (!timeout) {
-			mutex_unlock(&psp->mutex);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto exit;
 		}
 	}
 
@@ -316,8 +320,10 @@  psp_cmd_submit_buf(struct psp_context *psp,
 		ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
 		ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
 	}
-	mutex_unlock(&psp->mutex);
 
+exit:
+	mutex_unlock(&psp->mutex);
+	drm_dev_exit(idx);
 	return ret;
 }
 
@@ -354,8 +360,7 @@  static int psp_load_toc(struct psp_context *psp,
 	if (!cmd)
 		return -ENOMEM;
 	/* Copy toc to psp firmware private buffer */
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-	memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
+	psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size);
 
 	psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size);
 
@@ -570,8 +575,7 @@  static int psp_asd_load(struct psp_context *psp)
 	if (!cmd)
 		return -ENOMEM;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-	memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
+	psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
 
 	psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
 				  psp->asd_ucode_size);
@@ -726,8 +730,7 @@  static int psp_xgmi_load(struct psp_context *psp)
 	if (!cmd)
 		return -ENOMEM;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-	memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
+	psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
 
 	psp_prep_ta_load_cmd_buf(cmd,
 				 psp->fw_pri_mc_addr,
@@ -982,8 +985,7 @@  static int psp_ras_load(struct psp_context *psp)
 	if (!cmd)
 		return -ENOMEM;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-	memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
+	psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
 
 	psp_prep_ta_load_cmd_buf(cmd,
 				 psp->fw_pri_mc_addr,
@@ -1219,8 +1221,7 @@  static int psp_hdcp_load(struct psp_context *psp)
 	if (!cmd)
 		return -ENOMEM;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-	memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
+	psp_copy_fw(psp, psp->ta_hdcp_start_addr,
 	       psp->ta_hdcp_ucode_size);
 
 	psp_prep_ta_load_cmd_buf(cmd,
@@ -1366,8 +1367,7 @@  static int psp_dtm_load(struct psp_context *psp)
 	if (!cmd)
 		return -ENOMEM;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-	memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
+	psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
 
 	psp_prep_ta_load_cmd_buf(cmd,
 				 psp->fw_pri_mc_addr,
@@ -1507,8 +1507,7 @@  static int psp_rap_load(struct psp_context *psp)
 	if (!cmd)
 		return -ENOMEM;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-	memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
+	psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
 
 	psp_prep_ta_load_cmd_buf(cmd,
 				 psp->fw_pri_mc_addr,
@@ -2778,6 +2777,20 @@  static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
 	return count;
 }
 
+void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size)
+{
+	int idx;
+
+	if (!drm_dev_enter(&psp->adev->ddev, &idx))
+		return;
+
+	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
+	memcpy(psp->fw_pri_buf, start_addr, bin_size);
+
+	drm_dev_exit(idx);
+}
+
+
 static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
 		   psp_usbc_pd_fw_sysfs_read,
 		   psp_usbc_pd_fw_sysfs_write);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
index da250bc..ac69314 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
@@ -400,4 +400,7 @@  int psp_init_ta_microcode(struct psp_context *psp,
 			  const char *chip_name);
 int psp_get_fw_attestation_records_addr(struct psp_context *psp,
 					uint64_t *output_ptr);
+
+void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size);
+
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index 1a612f5..d656494 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -35,6 +35,8 @@ 
 #include "amdgpu.h"
 #include "atom.h"
 
+#include <drm/drm_drv.h>
+
 /*
  * Rings
  * Most engines on the GPU are fed via ring buffers.  Ring
@@ -463,3 +465,71 @@  int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
 	ring->sched.ready = !r;
 	return r;
 }
+
+void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
+{
+	int idx;
+	int i = 0;
+
+	if (!drm_dev_enter(&ring->adev->ddev, &idx))
+		return;
+
+	while (i <= ring->buf_mask)
+		ring->ring[i++] = ring->funcs->nop;
+
+	drm_dev_exit(idx);
+
+}
+
+void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
+{
+	int idx;
+
+	if (!drm_dev_enter(&ring->adev->ddev, &idx))
+		return;
+
+	if (ring->count_dw <= 0)
+		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
+	ring->ring[ring->wptr++ & ring->buf_mask] = v;
+	ring->wptr &= ring->ptr_mask;
+	ring->count_dw--;
+
+	drm_dev_exit(idx);
+}
+
+void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
+					      void *src, int count_dw)
+{
+	unsigned occupied, chunk1, chunk2;
+	void *dst;
+	int idx;
+
+	if (!drm_dev_enter(&ring->adev->ddev, &idx))
+		return;
+
+	if (unlikely(ring->count_dw < count_dw))
+		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
+
+	occupied = ring->wptr & ring->buf_mask;
+	dst = (void *)&ring->ring[occupied];
+	chunk1 = ring->buf_mask + 1 - occupied;
+	chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
+	chunk2 = count_dw - chunk1;
+	chunk1 <<= 2;
+	chunk2 <<= 2;
+
+	if (chunk1)
+		memcpy(dst, src, chunk1);
+
+	if (chunk2) {
+		src += chunk1;
+		dst = (void *)ring->ring;
+		memcpy(dst, src, chunk2);
+	}
+
+	ring->wptr += count_dw;
+	ring->wptr &= ring->ptr_mask;
+	ring->count_dw -= count_dw;
+
+	drm_dev_exit(idx);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index accb243..f90b81f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -300,53 +300,12 @@  static inline void amdgpu_ring_set_preempt_cond_exec(struct amdgpu_ring *ring,
 	*ring->cond_exe_cpu_addr = cond_exec;
 }
 
-static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
-{
-	int i = 0;
-	while (i <= ring->buf_mask)
-		ring->ring[i++] = ring->funcs->nop;
-
-}
-
-static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
-{
-	if (ring->count_dw <= 0)
-		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
-	ring->ring[ring->wptr++ & ring->buf_mask] = v;
-	ring->wptr &= ring->ptr_mask;
-	ring->count_dw--;
-}
+void amdgpu_ring_clear_ring(struct amdgpu_ring *ring);
 
-static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
-					      void *src, int count_dw)
-{
-	unsigned occupied, chunk1, chunk2;
-	void *dst;
-
-	if (unlikely(ring->count_dw < count_dw))
-		DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
-
-	occupied = ring->wptr & ring->buf_mask;
-	dst = (void *)&ring->ring[occupied];
-	chunk1 = ring->buf_mask + 1 - occupied;
-	chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
-	chunk2 = count_dw - chunk1;
-	chunk1 <<= 2;
-	chunk2 <<= 2;
+void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v);
 
-	if (chunk1)
-		memcpy(dst, src, chunk1);
-
-	if (chunk2) {
-		src += chunk1;
-		dst = (void *)ring->ring;
-		memcpy(dst, src, chunk2);
-	}
-
-	ring->wptr += count_dw;
-	ring->wptr &= ring->ptr_mask;
-	ring->count_dw -= count_dw;
-}
+void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
+					      void *src, int count_dw);
 
 int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
index bd4248c..b3ce5be 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
@@ -269,10 +269,8 @@  static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy PSP KDB binary to memory */
-	memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
+	psp_copy_fw(psp, psp->kdb_start_addr, psp->kdb_bin_size);
 
 	/* Provide the PSP KDB to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -302,10 +300,8 @@  static int psp_v11_0_bootloader_load_spl(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy PSP SPL binary to memory */
-	memcpy(psp->fw_pri_buf, psp->spl_start_addr, psp->spl_bin_size);
+	psp_copy_fw(psp, psp->spl_start_addr, psp->spl_bin_size);
 
 	/* Provide the PSP SPL to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -335,10 +331,8 @@  static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy PSP System Driver binary to memory */
-	memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
+	psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
 
 	/* Provide the sys driver to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -371,10 +365,8 @@  static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy Secure OS binary to PSP memory */
-	memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
+	psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
 
 	/* Provide the PSP secure OS to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
index c4828bd..618e5b6 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
@@ -138,10 +138,8 @@  static int psp_v12_0_bootloader_load_sysdrv(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy PSP System Driver binary to memory */
-	memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
+	psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
 
 	/* Provide the sys driver to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -179,10 +177,8 @@  static int psp_v12_0_bootloader_load_sos(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy Secure OS binary to PSP memory */
-	memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
+	psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
 
 	/* Provide the PSP secure OS to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
index f2e725f..d0a6cccd 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
@@ -102,10 +102,8 @@  static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy PSP System Driver binary to memory */
-	memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
+	psp_copy_fw(psp, psp->sys_start_addr, psp->sys_bin_size);
 
 	/* Provide the sys driver to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -143,10 +141,8 @@  static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
 	if (ret)
 		return ret;
 
-	memset(psp->fw_pri_buf, 0, PSP_1_MEG);
-
 	/* Copy Secure OS binary to PSP memory */
-	memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
+	psp_copy_fw(psp, psp->sos_start_addr, psp->sos_bin_size);
 
 	/* Provide the PSP secure OS to bootloader */
 	WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,