1. Added VF logic in amdgpu_virt to init IP discovery using the offsets from 
dynamic(v2) critical regions;
2. Added VF logic in amdgpu_virt to init bios image using the offsets from 
dynamic(v2) critical regions;

Signed-off-by: Ellen Pan <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c      |  26 +++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |  33 +++---
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c      | 107 ++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h      |   2 +
 5 files changed, 142 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 2a0df4cabb99..d320118858bc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -416,6 +416,7 @@ int amdgpu_device_ip_block_add(struct amdgpu_device *adev,
 /*
  * BIOS.
  */
+bool amdgpu_check_atom_bios(struct amdgpu_device *adev, size_t size);
 bool amdgpu_get_bios(struct amdgpu_device *adev);
 bool amdgpu_read_bios(struct amdgpu_device *adev);
 bool amdgpu_soc15_read_bios_from_rom(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 00e96419fcda..787584956214 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -47,7 +47,7 @@
 /* Check if current bios is an ATOM BIOS.
  * Return true if it is ATOM BIOS. Otherwise, return false.
  */
-static bool check_atom_bios(struct amdgpu_device *adev, size_t size)
+bool amdgpu_check_atom_bios(struct amdgpu_device *adev, size_t size)
 {
        uint16_t tmp, bios_header_start;
        uint8_t *bios = adev->bios;
@@ -96,7 +96,8 @@ void amdgpu_bios_release(struct amdgpu_device *adev)
  * part of the system bios.  On boot, the system bios puts a
  * copy of the igp rom at the start of vram if a discrete card is
  * present.
- * For SR-IOV, the vbios image is also put in VRAM in the VF.
+ * For SR-IOV, if dynamic critical region is not enabled,
+ * the vbios image is also put at the start of VRAM in the VF.
  */
 static bool amdgpu_read_bios_from_vram(struct amdgpu_device *adev)
 {
@@ -127,7 +128,7 @@ static bool amdgpu_read_bios_from_vram(struct amdgpu_device 
*adev)
        memcpy_fromio(adev->bios, bios, size);
        iounmap(bios);
 
-       if (!check_atom_bios(adev, size)) {
+       if (!amdgpu_check_atom_bios(adev, size)) {
                amdgpu_bios_release(adev);
                return false;
        }
@@ -155,7 +156,7 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
        memcpy_fromio(adev->bios, bios, size);
        pci_unmap_rom(adev->pdev, bios);
 
-       if (!check_atom_bios(adev, size)) {
+       if (!amdgpu_check_atom_bios(adev, size)) {
                amdgpu_bios_release(adev);
                return false;
        }
@@ -195,7 +196,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device 
*adev)
        /* read complete BIOS */
        amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
 
-       if (!check_atom_bios(adev, len)) {
+       if (!amdgpu_check_atom_bios(adev, len)) {
                amdgpu_bios_release(adev);
                return false;
        }
@@ -225,7 +226,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device 
*adev)
        memcpy_fromio(adev->bios, bios, romlen);
        iounmap(bios);
 
-       if (!check_atom_bios(adev, romlen))
+       if (!amdgpu_check_atom_bios(adev, romlen))
                goto free_bios;
 
        adev->bios_size = romlen;
@@ -334,7 +335,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
                        break;
        }
 
-       if (!check_atom_bios(adev, size)) {
+       if (!amdgpu_check_atom_bios(adev, size)) {
                amdgpu_bios_release(adev);
                return false;
        }
@@ -399,7 +400,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device 
*adev)
                                             vhdr->ImageLength,
                                             GFP_KERNEL);
 
-                       if (!check_atom_bios(adev, vhdr->ImageLength)) {
+                       if (!amdgpu_check_atom_bios(adev, vhdr->ImageLength)) {
                                amdgpu_bios_release(adev);
                                return false;
                        }
@@ -467,9 +468,14 @@ static bool amdgpu_get_bios_dgpu(struct amdgpu_device 
*adev)
        }
 
        /* this is required for SR-IOV */
-       if (amdgpu_read_bios_from_vram(adev)) {
-               dev_info(adev->dev, "Fetched VBIOS from VRAM BAR\n");
+       if (amdgpu_sriov_vf(adev) && amdgpu_virt_read_bios_from_vram(adev)) {
+               dev_info(adev->dev, "Fetched VBIOS from dynamic VRAM BAR\n");
                goto success;
+       } else {
+               if (amdgpu_read_bios_from_vram(adev)) {
+                       dev_info(adev->dev, "Fetched VBIOS from VRAM BAR\n");
+                       goto success;
+               }
        }
 
        if (amdgpu_prefer_rom_resource(adev)) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 73401f0aeb34..de8676d6ff9c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -275,21 +275,18 @@ static int amdgpu_discovery_read_binary_from_mem(struct 
amdgpu_device *adev,
        int i, ret = 0;
        u32 msg;
 
-       if (!amdgpu_sriov_vf(adev)) {
-               /* It can take up to two second for IFWI init to complete on 
some dGPUs,
-                * but generally it should be in the 60-100ms range.  Normally 
this starts
-                * as soon as the device gets power so by the time the OS loads 
this has long
-                * completed.  However, when a card is hotplugged via e.g., 
USB4, we need to
-                * wait for this to complete.  Once the C2PMSG is updated, we 
can
-                * continue.
-                */
-
-               for (i = 0; i < 2000; i++) {
-                       msg = RREG32(mmMP0_SMN_C2PMSG_33);
-                       if (msg & 0x80000000)
-                               break;
-                       msleep(1);
-               }
+       /* It can take up to two second for IFWI init to complete on some dGPUs,
+        * but generally it should be in the 60-100ms range.  Normally this 
starts
+        * as soon as the device gets power so by the time the OS loads this 
has long
+        * completed.  However, when a card is hotplugged via e.g., USB4, we 
need to
+        * wait for this to complete.  Once the C2PMSG is updated, we can
+        * continue.
+        */
+       for (i = 0; i < 2000; i++) {
+               msg = RREG32(mmMP0_SMN_C2PMSG_33);
+               if (msg & 0x80000000)
+                       break;
+               msleep(1);
        }
 
        vram_size = RREG32(mmRCC_CONFIG_MEMSIZE);
@@ -467,8 +464,10 @@ static int amdgpu_discovery_init(struct amdgpu_device 
*adev)
                        goto out;
        } else {
                drm_dbg(&adev->ddev, "use ip discovery information from 
memory");
-               r = amdgpu_discovery_read_binary_from_mem(
-                       adev, adev->mman.discovery_bin);
+               if (amdgpu_sriov_vf(adev))
+                       r = amdgpu_virt_init_discovery_from_mem(adev, 
adev->mman.discovery_bin);
+               else
+                       r = amdgpu_discovery_read_binary_from_mem(adev, 
adev->mman.discovery_bin);
                if (r)
                        goto out;
        }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
index 461e83728594..67d5f15a72a1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
@@ -965,6 +965,113 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device 
*adev)
        return r;
 }
 
+int amdgpu_virt_init_discovery_from_mem(struct amdgpu_device *adev, uint8_t 
*binary)
+{
+       uint64_t vram_size;
+       uint32_t ip_discovery_offset, ip_discovery_size;
+       uint64_t pos = 0;
+
+       /* Get dynamic offset for IPD if dynamic critical region is enabled */
+       if (adev->virt.is_dynamic_crit_regn_enabled) {
+               ip_discovery_offset =
+                       
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset;
+               ip_discovery_size =
+                       
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb << 10;
+
+               dev_info(adev->dev,
+                       "Got IPD info from dynamic crit_region at offset 0x%x 
with size of 0x%x bytes.\n",
+                       ip_discovery_offset, ip_discovery_size);
+
+               if (!IS_ALIGNED(ip_discovery_offset, 4) || 
!IS_ALIGNED(ip_discovery_size, 4)) {
+                       dev_err(adev->dev, "IP discovery data not aligned to 4 
bytes\n");
+                       return -EINVAL;
+               }
+
+               if (ip_discovery_size > DISCOVERY_TMR_SIZE) {
+                       dev_err(adev->dev, "Invalid IP discovery size: 0x%x\n", 
ip_discovery_size);
+                       return -EINVAL;
+               }
+
+               pos = (uint64_t)ip_discovery_offset;
+               amdgpu_device_vram_access(adev, pos, (uint32_t *)binary,
+                                       ip_discovery_size, false);
+       } else {
+               vram_size = RREG32(mmRCC_CONFIG_MEMSIZE);
+               if (!vram_size || vram_size == U32_MAX)
+                       return -EINVAL;
+
+               vram_size <<= 20;
+
+               pos = vram_size - DISCOVERY_TMR_OFFSET;
+               amdgpu_device_vram_access(adev, pos, (uint32_t *)binary,
+                                       adev->mman.discovery_tmr_size, false);
+       }
+
+       return 0;
+}
+
+/* For SR-IOV, if dynamic critical region is enabled,
+ * the vbios image is put at a dynamic offset of VRAM in the VF.
+ * If dynamic critical region is disabled, exit early to proceed
+ * the same seq as on baremetal.
+ */
+bool amdgpu_virt_read_bios_from_vram(struct amdgpu_device *adev)
+{
+       uint8_t __iomem *bios;
+       resource_size_t vram_base;
+       resource_size_t size = 256 * 1024; /* ??? */
+       uint32_t vbios_offset = 0;
+       uint32_t vbios_size = 0;
+
+       /* Exit early if it's not initialized */
+       if (!adev->virt.is_dynamic_crit_regn_enabled)
+               return false;
+
+       if (amdgpu_device_need_post(adev))
+               return false;
+
+       /* FB BAR not enabled */
+       if (pci_resource_len(adev->pdev, 0) == 0)
+               return false;
+
+       adev->bios = NULL;
+       vram_base = pci_resource_start(adev->pdev, 0);
+
+       vbios_offset = 
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].offset;
+       vbios_size =
+               
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].size_kb << 10;
+       if (vbios_size > size) {
+               dev_err(adev->dev, "Invalid vbios size: 0x%x\n", vbios_size);
+               return false;
+       }
+
+       dev_info(adev->dev,
+               "Got bios info from dynamic crit_region_table at offset 0x%x 
with size of 0x%x bytes.\n",
+               vbios_offset, vbios_size);
+
+       size = vbios_size;
+
+       bios = ioremap_wc(vram_base + vbios_offset, size);
+       if (!bios)
+               return false;
+
+       adev->bios = kmalloc(size, GFP_KERNEL);
+       if (!adev->bios) {
+               iounmap(bios);
+               return false;
+       }
+       adev->bios_size = size;
+       memcpy_fromio(adev->bios, bios, size);
+       iounmap(bios);
+
+       if (!check_atom_bios(adev, size)) {
+               amdgpu_bios_release(adev);
+               return false;
+       }
+
+       return true;
+}
+
 void amdgpu_virt_init(struct amdgpu_device *adev)
 {
        bool is_sriov = false;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
index bc1fc1c6daba..f2aa306f4192 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
@@ -438,6 +438,8 @@ void amdgpu_virt_fini_data_exchange(struct amdgpu_device 
*adev);
 void amdgpu_virt_init(struct amdgpu_device *adev);
 
 int amdgpu_virt_init_critical_region(struct amdgpu_device *adev);
+int amdgpu_virt_init_discovery_from_mem(struct amdgpu_device *adev, uint8_t 
*binary);
+bool amdgpu_virt_read_bios_from_vram(struct amdgpu_device *adev);
 
 bool amdgpu_virt_can_access_debugfs(struct amdgpu_device *adev);
 int amdgpu_virt_enable_access_debugfs(struct amdgpu_device *adev);
-- 
2.34.1

Reply via email to