diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 28586e46c604..31f10e631118 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4259,7 +4259,15 @@ int amdgpu_device_init(struct amdgpu_device *adev, PCI_EXP_DEVCAP2_ATOMIC_COMP64); } #elif defined(__FreeBSD__) - adev->have_atomics_support = false; + /* APUs w/ gfx9 onwards don't rely on PCIe atomics: the internal path + * natively supports atomics, so enable it (mirrors the __linux__ case). + * Without this the userspace gfx submission path stalls the gfx ring. + */ + if ((adev->flags & AMD_IS_APU) && + (amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0))) + adev->have_atomics_support = true; + else + adev->have_atomics_support = false; #endif if (!adev->have_atomics_support) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 45ed97038df0..d4c5884629c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -4109,6 +4109,16 @@ static void gfx_v10_0_check_gfxoff_flag(struct amdgpu_device *adev) if (!gfx_v10_0_navi10_gfxoff_should_enable(adev)) adev->pm.pp_feature &= ~PP_GFXOFF_MASK; break; +#ifdef __FreeBSD__ + case IP_VERSION(10, 3, 6): + /* Raphael APU: GFXOFF wake via SMU is broken under LinuxKPI, + * leaving the gfx ring stuck (ring gfx_0.0.0 timeout) followed + * by a GPU reset loop. Disable GFXOFF until the SMU handshake + * works on FreeBSD. + */ + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; + break; +#endif default: break; } @@ -7163,6 +7173,31 @@ static int gfx_v10_0_cp_resume(struct amdgpu_device *adev) return r; } +#ifdef __FreeBSD__ + /* + * On this APU under LinuxKPI the doorbell does not wake the CP/MEC + * once a queue has gone idle, so GPU-scheduler submissions issued + * after the boot-time idle-poll window are never fetched (ring + * gfx_0.0.0 timeout, signaled seq < emitted seq, with no VM fault). + * Keep the engines polling the queue write pointer from memory rather + * than relying on a doorbell wake: aim the GFX-pipe wptr poll at the + * ring's wptr writeback, max out the idle poll count, and enable MEC + * wptr polling (per-queue poll address comes from each MQD). + */ + if (adev->gfx.num_gfx_rings) { + uint64_t wptr_gpu_addr = adev->gfx.gfx_ring[0].wptr_gpu_addr; + + WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_LO, + lower_32_bits(wptr_gpu_addr)); + WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_HI, + upper_32_bits(wptr_gpu_addr)); + } + WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_CNTL, + (0x0100 << CP_RB_WPTR_POLL_CNTL__POLL_FREQUENCY__SHIFT) | + (0xffff << CP_RB_WPTR_POLL_CNTL__IDLE_POLL_COUNT__SHIFT)); + WREG32_FIELD15(GC, 0, CP_PQ_WPTR_POLL_CNTL, EN, 1); +#endif + return 0; }