On iMac20,2 the Radeon Pro 5700 (1002:731b, Apple subsystem 106b:021a)
fails to initialize on approximately half of all boots. The SMU replies
to GetSmuVersion and GetDriverIfVersion, then does not reply to
EnableAllSmuFeatures:

  amdgpu 0000:03:00.0: SMU: No response msg_reg: 6 resp_reg: 0
  amdgpu 0000:03:00.0: Failed to enable requested dpm features!
  amdgpu 0000:03:00.0: hw_init of IP block <smu> failed -62

A second bind of the driver recovers the GPU each time (86 of 86
failures). The failed probe has loaded the PSP. On the second probe,
nv_need_reset_on_init() reads a sign of life in MP0_SMN_C2PMSG_81, so
the driver does a mode1 reset and a vPOST before it initializes the IP
blocks.

A reset on init is not possible on the first probe. If the driver tries
a reset on init, psp_v11_0_mode1_reset() times out on
MBOX_TOS_READY_FLAG, because Apple's firmware does not load the PSP, and
the probe fails. The PSP is then still not loaded, and a later bind
cannot recover the GPU.

Because of this, on this board, return -EPROBE_DEFER when
amdgpu_device_ip_init() fails with -ETIME, this attempt did no reset on
init, and the ASIC now reports that it needs one. The failed init
unwinds as before. When the driver core probes the device again, the
probe takes the existing reset-on-init path. The decision uses only
local state: the retry has reset the ASIC, so it cannot defer again,
and a first attempt that did not load the PSP does not defer.

The retry is not done in amdgpu_pci_probe(). adev is devm allocated and
amdgpu_device_init() is not re-entrant, so a retry there needs a second
adev for the same pci_dev while the first is torn down.

The driver core probes a deferred device again only when another driver
binds, or when the deferred probe timeout expires. On this board other
drivers bind during the SMU timeout, so the retry starts almost
immediately. If no driver binds, the GPU stays deferred and the kernel
writes no "probe failed" line. dev_err_probe() records the reason, and
/sys/kernel/debug/devices_deferred shows it.

Tested on iMac20,2 with v7.2.3, built against the 7.2.3 headers: 30 of
30 boots initialized the GPU without user space intervention. The first
probe timed out on 14 of them, and each deferred retry succeeded after
a mode1 reset.

Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5726
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Teemu Haila <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 44 ++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index fa67de6..600479d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3746,6 +3746,40 @@ amdgpu_device_should_register_switcheroo(struct 
amdgpu_device *adev, bool px)
                       apple_gmux_detect(NULL, NULL)));
 }
 
+/*
+ * On some Apple boards, the first probe after the pre-OS driver times out in
+ * SMU hw_init.  A reset on init recovers the ASIC, but the PSP does the reset,
+ * and the PSP is not loaded on the first probe.  The failed probe loads the
+ * PSP, so a retry resets the ASIC and succeeds.  Because of this, defer the
+ * probe on these boards instead of failing it.
+ */
+struct amdgpu_probe_retry_quirk {
+       u16 device;
+       u16 subsystem_vendor;
+       u16 subsystem_device;
+       u8 revision;
+};
+
+static const struct amdgpu_probe_retry_quirk amdgpu_probe_retry_quirks[] = {
+       { 0x731b, PCI_VENDOR_ID_APPLE, 0x021a, 0x40 }, /* Radeon Pro 5700, 
iMac20,2 */
+};
+
+static bool amdgpu_device_probe_retry_quirk(struct amdgpu_device *adev)
+{
+       struct pci_dev *pdev = adev->pdev;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(amdgpu_probe_retry_quirks); i++) {
+               if (pdev->device == amdgpu_probe_retry_quirks[i].device &&
+                   pdev->subsystem_vendor == 
amdgpu_probe_retry_quirks[i].subsystem_vendor &&
+                   pdev->subsystem_device == 
amdgpu_probe_retry_quirks[i].subsystem_device &&
+                   pdev->revision == amdgpu_probe_retry_quirks[i].revision)
+                       return true;
+       }
+
+       return false;
+}
+
 /**
  * amdgpu_device_init - initialize the driver
  *
@@ -3761,6 +3795,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
 {
        struct pci_dev *pdev = adev->pdev;
        int r, i;
+       bool reset_on_init = false;
        bool px = false;
        u32 max_MBps;
        int tmp;
@@ -4037,6 +4072,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
         *  E.g., driver was not cleanly unloaded previously, etc.
         */
        if (!amdgpu_sriov_vf(adev) && amdgpu_asic_need_reset_on_init(adev)) {
+               reset_on_init = true;
                if (adev->gmc.xgmi.num_physical_nodes) {
                        dev_info(adev->dev, "Pending hive reset.\n");
                        amdgpu_set_init_level(adev,
@@ -4110,6 +4146,14 @@ fence_driver_init:
        if (r) {
                dev_err(adev->dev, "amdgpu_device_ip_init failed\n");
                amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 
0);
+               if (r == -ETIME && !reset_on_init &&
+                   amdgpu_device_probe_retry_quirk(adev) &&
+                   amdgpu_asic_need_reset_on_init(adev)) {
+                       dev_warn(adev->dev,
+                                "init timed out before the ASIC could be 
reset, deferring the probe to retry with a reset on init\n");
+                       r = dev_err_probe(adev->dev, -EPROBE_DEFER,
+                                         "init timed out before the ASIC could 
be reset, deferring the probe to retry with a reset on init\n");
+               }
                goto release_ras_con;
        }
 

base-commit: a24db07159cdd27eba171278366670e9a6c9643f
-- 
2.55.0

Reply via email to