Adds support for IP discovery via PSP mailbox using guest phys
addr for passthrough A+A.

Keep the discovery firmware file as the preferred source. Use the
mailbox only when no firmware file is selected and the device is in
passthrough with a zero-sized BAR0.

The mailbox registers are fixed MMIO indexes. This runs before IP
discovery has programmed the hardware register bases.

Signed-off-by: Dejan Andjelkovic <[email protected]>
---
v5 -> v6:
- Drop the post-wait status read in amdgpu_psp_read_discovery().

 drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  5 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |  6 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c       | 61 +++++++++++++++++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h       |  2 +
 drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h       |  4 +-
 5 files changed, 71 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 5a32b54b1e9b..20570ab1d2c0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1019,6 +1019,11 @@ static inline struct amdgpu_device 
*amdgpu_ttm_adev(struct ttm_device *bdev)
        return container_of(bdev, struct amdgpu_device, mman.bdev);
 }
 
+static inline bool amdgpu_is_spm_passthrough(struct amdgpu_device *adev)
+{
+       return amdgpu_passthrough(adev) && !pci_resource_len(adev->pdev, 0);
+}
+
 static inline bool amdgpu_is_multi_aid(struct amdgpu_device *adev)
 {
        return !!adev->aid_mask;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 79a2b1268b23..8b976e363f16 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -771,6 +771,12 @@ static int amdgpu_discovery_init(struct amdgpu_device 
*adev)
                                                           fw_name);
                if (r)
                        goto out;
+       } else if (amdgpu_is_spm_passthrough(adev)) {
+               drm_dbg(&adev->ddev, "use ip discovery information from psp 
mailbox\n");
+               r = amdgpu_psp_read_discovery(adev, discovery_bin,
+                                             
GFX_CTRL_ADDR_TYPE_GUEST_PHY_ADDR);
+               if (r)
+                       goto out;
        } else {
                drm_dbg(&adev->ddev, "use ip discovery information from 
memory\n");
                r = amdgpu_discovery_read_binary_from_mem(adev, discovery_bin,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index c0ed3e24b684..50861175d661 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -52,6 +52,12 @@
 
 #define PSP_IRQ_DEFAULT_HANDLER_ID 0xFFFFFFFF
 
+/* Note: These are pre-IP-discovery fixed MMIO indexes */
+#define mmMP0_SMN_C2PMSG_64_MMIO       0x16080
+#define mmMP0_SMN_C2PMSG_69_MMIO       0x16085
+#define mmMP0_SMN_C2PMSG_70_MMIO       0x16086
+#define mmMP0_SMN_C2PMSG_71_MMIO       0x16087
+
 static int psp_load_smu_fw(struct psp_context *psp);
 static int psp_rap_terminate(struct psp_context *psp);
 static int psp_securedisplay_terminate(struct psp_context *psp);
@@ -761,17 +767,13 @@ static int psp_sw_fini(struct amdgpu_ip_block *ip_block)
        return 0;
 }
 
-int psp_wait_for(struct psp_context *psp, uint32_t reg_index, uint32_t reg_val,
-                uint32_t mask, uint32_t flags)
+static int __psp_wait_for(struct amdgpu_device *adev, uint32_t reg_index, 
uint32_t reg_val,
+                         uint32_t mask, uint32_t flags)
 {
        bool check_changed = flags & PSP_WAITREG_CHANGED;
        bool verbose = !(flags & PSP_WAITREG_NOVERBOSE);
        uint32_t val;
        int i;
-       struct amdgpu_device *adev = psp->adev;
-
-       if (psp->adev->no_hw_access)
-               return 0;
 
        for (i = 0; i < adev->usec_timeout; i++) {
                val = RREG32(reg_index);
@@ -793,6 +795,17 @@ int psp_wait_for(struct psp_context *psp, uint32_t 
reg_index, uint32_t reg_val,
        return -ETIME;
 }
 
+int psp_wait_for(struct psp_context *psp, uint32_t reg_index, uint32_t reg_val,
+                uint32_t mask, uint32_t flags)
+{
+       struct amdgpu_device *adev = psp->adev;
+
+       if (psp->adev->no_hw_access)
+               return 0;
+
+       return __psp_wait_for(adev, reg_index, reg_val, mask, flags);
+}
+
 int psp_wait_for_spirom_update(struct psp_context *psp, uint32_t reg_index,
                               uint32_t reg_val, uint32_t mask, uint32_t 
msec_timeout)
 {
@@ -3347,6 +3360,42 @@ int psp_securedisplay_invoke(struct psp_context *psp, 
uint32_t ta_cmd_id)
 }
 /* SECUREDISPLAY end */
 
+int amdgpu_psp_read_discovery(struct amdgpu_device *adev, uint8_t *binary,
+                             GFX_CTRL_ADDR_TYPE addr_type)
+{
+       void *cpu_addr;
+       dma_addr_t dma_addr;
+       u32 length;
+       int ret;
+
+       cpu_addr = dma_alloc_coherent(adev->dev, adev->discovery.size,
+                                     &dma_addr, GFP_KERNEL);
+       if (!cpu_addr)
+               return -ENOMEM;
+
+       length = adev->discovery.size;
+       length = (length & 0x0fffffffU) | ((u32)addr_type << 28);
+
+       WREG32(mmMP0_SMN_C2PMSG_69_MMIO, lower_32_bits((u64)dma_addr));
+       WREG32(mmMP0_SMN_C2PMSG_70_MMIO, upper_32_bits((u64)dma_addr));
+       WREG32(mmMP0_SMN_C2PMSG_71_MMIO, length);
+
+       WREG32(mmMP0_SMN_C2PMSG_64_MMIO, GFX_CTRL_CMD_ID_GET_IP_DISCOVERY);
+
+       ret = __psp_wait_for(adev, mmMP0_SMN_C2PMSG_64_MMIO,
+                            MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK,
+                            PSP_WAITREG_NOVERBOSE);
+       if (ret) {
+               dev_err(adev->dev, "ip_discovery: PSP cmd failed\n");
+       } else {
+               memcpy(binary, cpu_addr, adev->discovery.size);
+       }
+
+       dma_free_coherent(adev->dev, adev->discovery.size, cpu_addr, dma_addr);
+
+       return ret;
+}
+
 int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev)
 {
        struct psp_context *psp = &adev->psp;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
index 975d12359358..fe3d053d9924 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
@@ -688,6 +688,8 @@ int psp_memory_partition(struct psp_context *psp, int mode);
 
 int is_psp_fw_valid(struct psp_bin_desc bin);
 
+int amdgpu_psp_read_discovery(struct amdgpu_device *adev, uint8_t *binary,
+                             GFX_CTRL_ADDR_TYPE addr_type);
 int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev);
 bool amdgpu_psp_get_ras_capability(struct psp_context *psp);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h 
b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
index 49aa95c76745..d13ae1756887 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
+++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
@@ -49,6 +49,7 @@ enum psp_gfx_crtl_cmd_id
     GFX_CTRL_CMD_ID_GBR_IH_SET      = 0x00080000,   /* set Gbr IH_RB_CNTL 
registers */
     GFX_CTRL_CMD_ID_CONSUME_CMD     = 0x00090000,   /* send interrupt to psp 
for updating write pointer of vf */
     GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING = 0x000C0000, /* destroy GPCOM ring */
+    GFX_CTRL_CMD_ID_GET_IP_DISCOVERY   = 0x000D0000, /* Copy IP_DISCOVERY_DATA 
to host-specified address */
 
     GFX_CTRL_CMD_ID_MAX             = 0x000F0000,   /* max command ID */
 };
@@ -58,7 +59,8 @@ typedef enum
     GFX_CTRL_ADDR_TYPE_AUTO_DETECT = 0,
     GFX_CTRL_ADDR_TYPE_SYS_PHY_ADDR,
     GFX_CTRL_ADDR_TYPE_GPU_PHY_ADDR,
-    GFX_CTRL_ADDR_TYPE_GPU_VIRT_ADDR
+    GFX_CTRL_ADDR_TYPE_GPU_VIRT_ADDR,
+    GFX_CTRL_ADDR_TYPE_GUEST_PHY_ADDR
 }  GFX_CTRL_ADDR_TYPE;
 
 /*-----------------------------------------------------------------------------
-- 
2.43.0

Reply via email to