AMD General

> -----Original Message-----
> From: amd-gfx <[email protected]> On Behalf Of Alex
> Deucher
> Sent: Wednesday, September 2, 2026 4:10 AM
> To: [email protected]; Koenig, Christian
> <[email protected]>
> Cc: Deucher, Alexander <[email protected]>
> Subject: [PATCH 22/31] drm/amdgpu/gmc: rework pasid flushing
>
> Split out all of the various flush methods and use the new pasid flush method 
> enum
> to determine which one to use.
>
> Signed-off-by: Alex Deucher <[email protected]>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 247 +++++++++++++++++++-----
>  drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c  |   2 +
>  drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c  |   2 +
>  drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c   |   2 +
>  4 files changed, 201 insertions(+), 52 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> index 8a975eddd75c7..2800eebe50649 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> @@ -788,9 +788,66 @@ void amdgpu_gmc_flush_gpu_tlb_gart(struct
> amdgpu_device *adev,
>       dev_err(adev->dev, "Error flushing GPU TLB using the SDMA (%d)!\n", r); 
>  }
>
> -int amdgpu_gmc_flush_gpu_tlb_pasid(struct amdgpu_device *adev, uint16_t 
> pasid,
> -                                uint32_t flush_type, bool all_hub,
> -                                uint32_t inst)
> +static int amdgpu_gmc_flush_gpu_tlb_sdma_helper(struct amdgpu_device *adev,
> +                                             uint16_t pasid, uint32_t 
> flush_type,
> +                                             bool all_hub, uint32_t inst)
> +{
> +     struct amdgpu_ring *ring;
> +     struct dma_fence *fence;
> +     struct amdgpu_job *job;
> +     uint16_t queried;
> +     /* Use register 17 for GART */
> +     u32 eng = 17;
> +     int vmid, r, i, ndw;
> +
> +     /* flush hdp cache */
> +     amdgpu_device_flush_hdp(adev, NULL);
> +
> +     ndw = ALIGN(adev->mman.buffer_funcs->tlb_inv_num_dw * 16 *
> AMDGPU_MAX_VMHUBS, 8);
> +     ring = to_amdgpu_ring(adev->mman.buffer_funcs_scheds[0]);
> +
> +     mutex_lock(&adev->mman.default_entity.lock);
> +     r = amdgpu_job_alloc_with_ib(ring->adev, &adev-
> >mman.default_entity.base,
> +                                  AMDGPU_FENCE_OWNER_UNDEFINED,
> +                                  ndw * 4, AMDGPU_IB_POOL_IMMEDIATE,
> +                                  AMDGPU_KERNEL_JOB_ID_VM_UPDATE,
> +                                  &job);
> +     if (r)
> +             goto exit;
> +
> +     for (vmid = 1; vmid < 16; vmid++) {
> +             bool valid;
> +
> +             valid = adev->gmc.gmc_funcs->get_vmid_pasid_mapping_info(adev,
> vmid, inst,
> +                                                                      
> &queried);
> +             if (!valid || queried != pasid)
> +                     continue;
> +
> +             if (all_hub) {
> +                     for_each_set_bit(i, adev->vmhubs_mask,
> AMDGPU_MAX_VMHUBS)
> +                             amdgpu_emit_tlb_inv(adev, &job->ibs[0], vmid, 
> i, eng,
> +                                                 flush_type, inst);
> +             } else {
> +                     amdgpu_emit_tlb_inv(adev, &job->ibs[0], vmid,
> AMDGPU_GFXHUB(inst), eng,
> +                                         flush_type, inst);
> +             }
> +     }
> +     amdgpu_ring_pad_ib(ring, &job->ibs[0]);
> +     fence = amdgpu_job_submit(job);
> +     mutex_unlock(&adev->mman.default_entity.lock);
           It should be double unlock, and  it unlocks again at exit.  we can 
remove it .
                Regards
            Jesse

> +
> +     dma_fence_wait(fence, false);
> +     dma_fence_put(fence);
> +
> +exit:
> +     mutex_unlock(&adev->mman.default_entity.lock);
> +
> +     return r;
> +}
> +
> +static int amdgpu_gmc_flush_gpu_tlb_kiq_helper(struct amdgpu_device *adev,
> +                                            uint16_t pasid, uint32_t 
> flush_type,
> +                                            bool all_hub, uint32_t inst)
>  {
>       struct amdgpu_ring *ring = &adev->gfx.kiq[inst].ring;
>       struct amdgpu_kiq *kiq = &adev->gfx.kiq[inst]; @@ -798,6 +855,110 @@
> int amdgpu_gmc_flush_gpu_tlb_pasid(struct amdgpu_device *adev, uint16_t pasid,
>       int r, cnt = 0;
>       uint32_t seq;
>
> +     /* 2 dwords flush + 8 dwords fence */
> +     ndw = kiq->pmf->invalidate_tlbs_size + 8;
> +
> +     if (adev->gmc.flush_tlb_needs_extra_type_2)
> +             ndw += kiq->pmf->invalidate_tlbs_size;
> +
> +     if (adev->gmc.flush_tlb_needs_extra_type_0)
> +             ndw += kiq->pmf->invalidate_tlbs_size;
> +
> +     spin_lock(&adev->gfx.kiq[inst].ring_lock);
> +     r = amdgpu_ring_alloc(ring, ndw);
> +     if (r) {
> +             spin_unlock(&adev->gfx.kiq[inst].ring_lock);
> +             return r;
> +     }
> +     if (adev->gmc.flush_tlb_needs_extra_type_2)
> +             kiq->pmf->kiq_invalidate_tlbs(ring, pasid, 2, all_hub);
> +
> +     if (flush_type == 2 && adev->gmc.flush_tlb_needs_extra_type_0)
> +             kiq->pmf->kiq_invalidate_tlbs(ring, pasid, 0, all_hub);
> +
> +     kiq->pmf->kiq_invalidate_tlbs(ring, pasid, flush_type, all_hub);
> +     r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT);
> +     if (r) {
> +             amdgpu_ring_undo(ring);
> +             spin_unlock(&adev->gfx.kiq[inst].ring_lock);
> +             return r;
> +     }
> +
> +     amdgpu_ring_commit(ring);
> +     spin_unlock(&adev->gfx.kiq[inst].ring_lock);
> +
> +     r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
> +
> +     might_sleep();
> +     while (r < 1 && cnt++ < MAX_KIQ_REG_TRY &&
> +            !amdgpu_reset_pending(adev->reset_domain)) {
> +             msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
> +             r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
> +     }
> +
> +     if (cnt > MAX_KIQ_REG_TRY) {
> +             dev_err(adev->dev, "timeout waiting for kiq fence\n");
> +             r = -ETIME;
> +     } else
> +             r = 0;
> +
> +     return r;
> +}
> +
> +static int amdgpu_gmc_flush_gpu_tlb_mes_helper(struct amdgpu_device *adev,
> +                                            uint16_t pasid, uint32_t 
> flush_type,
> +                                            bool all_hub, uint32_t inst) {
> +     struct mes_inv_tlbs_pasid_input input = {0};
> +     int r;
> +
> +     input.xcc_id = inst;
> +     input.pasid = pasid;
> +     input.flush_type = flush_type;
> +
> +     /* MES will invalidate hubs for the device(including slave xcc)
> +      * from master, ignore request from slave
> +      */
> +     if (!amdgpu_gfx_is_master_xcc(adev, inst))
> +             return -EINVAL;
> +
> +     input.hub_id = AMDGPU_GFXHUB(0);
> +     amdgpu_mes_lock(&adev->mes);
> +     r = adev->mes.funcs->invalidate_tlbs_pasid(&adev->mes, &input);
> +     amdgpu_mes_unlock(&adev->mes);
> +     if (r)
> +             return r;
> +
> +     if (all_hub) {
> +             /* invalidate mm_hub */
> +             if (test_bit(AMDGPU_MMHUB0(0), adev->vmhubs_mask)) {
> +                     input.hub_id = AMDGPU_MMHUB0(0);
> +                     amdgpu_mes_lock(&adev->mes);
> +                     r = adev->mes.funcs->invalidate_tlbs_pasid(&adev->mes,
> &input);
> +                     amdgpu_mes_unlock(&adev->mes);
> +                     if (r)
> +                             return r;
> +             }
> +             if (test_bit(AMDGPU_MMHUB1(0), adev->vmhubs_mask)) {
> +                     input.hub_id = AMDGPU_MMHUB1(0);
> +                     amdgpu_mes_lock(&adev->mes);
> +                     r = adev->mes.funcs->invalidate_tlbs_pasid(&adev->mes,
> &input);
> +                     amdgpu_mes_unlock(&adev->mes);
> +                     if (r)
> +                             return r;
> +             }
> +     }
> +     return 0;
> +}
> +
> +int amdgpu_gmc_flush_gpu_tlb_pasid(struct amdgpu_device *adev, uint16_t
> pasid,
> +                                uint32_t flush_type, bool all_hub,
> +                                uint32_t inst)
> +{
> +     struct amdgpu_ring *ring;
> +     bool use_mmio = false;
> +     int r;
> +
>       /*
>        * A GPU reset should flush all TLBs anyway, so no need to do
>        * this while one is ongoing.
> @@ -805,8 +966,38 @@ int amdgpu_gmc_flush_gpu_tlb_pasid(struct
> amdgpu_device *adev, uint16_t pasid,
>       if (!down_read_trylock(&adev->reset_domain->sem))
>               return 0;
>
> -     if (!adev->gmc.flush_pasid_uses_kiq || !ring->sched.ready) {
> +     switch (adev->gmc.pasid_inv_method) {
> +     case AMDGPU_TLB_INV_METHOD_MMIO:
> +     default:
> +             use_mmio = true;
> +             break;
> +     case AMDGPU_TLB_INV_METHOD_SDMA:
> +             ring = to_amdgpu_ring(adev->mman.buffer_funcs_scheds[0]);
> +             if (!ring->sched.ready)
> +                     use_mmio = true;
> +             else
> +                     r = amdgpu_gmc_flush_gpu_tlb_sdma_helper(adev, pasid,
> flush_type,
> +                                                              all_hub, inst);
> +             break;
> +     case AMDGPU_TLB_INV_METHOD_KIQ:
> +             ring = &adev->gfx.kiq[inst].ring;
> +             if (!adev->gmc.flush_pasid_uses_kiq || !ring->sched.ready)
> +                     use_mmio = true;
> +             else
> +                     r = amdgpu_gmc_flush_gpu_tlb_kiq_helper(adev, pasid,
> flush_type,
> +                                                             all_hub, inst);
> +             break;
> +     case AMDGPU_TLB_INV_METHOD_MES:
> +             ring = &adev->mes.ring[MES_PIPE_INST(inst, 0)];
> +             if (!ring->sched.ready)
> +                     use_mmio = true;
> +             else
> +                     r = amdgpu_gmc_flush_gpu_tlb_mes_helper(adev, pasid,
> flush_type,
> +                                                             all_hub, inst);
> +             break;
> +     }
>
> +     if (use_mmio) {
>               if (!adev->gmc.gmc_funcs->flush_gpu_tlb_pasid) {
>                       r = 0;
>                       goto error_unlock_reset;
> @@ -825,54 +1016,6 @@ int amdgpu_gmc_flush_gpu_tlb_pasid(struct
> amdgpu_device *adev, uint16_t pasid,
>               adev->gmc.gmc_funcs->flush_gpu_tlb_pasid(adev, pasid,
>                                                        flush_type, all_hub,
>                                                        inst);
> -             r = 0;
> -     } else {
> -             /* 2 dwords flush + 8 dwords fence */
> -             ndw = kiq->pmf->invalidate_tlbs_size + 8;
> -
> -             if (adev->gmc.flush_tlb_needs_extra_type_2)
> -                     ndw += kiq->pmf->invalidate_tlbs_size;
> -
> -             if (adev->gmc.flush_tlb_needs_extra_type_0)
> -                     ndw += kiq->pmf->invalidate_tlbs_size;
> -
> -             spin_lock(&adev->gfx.kiq[inst].ring_lock);
> -             r = amdgpu_ring_alloc(ring, ndw);
> -             if (r) {
> -                     spin_unlock(&adev->gfx.kiq[inst].ring_lock);
> -                     goto error_unlock_reset;
> -             }
> -             if (adev->gmc.flush_tlb_needs_extra_type_2)
> -                     kiq->pmf->kiq_invalidate_tlbs(ring, pasid, 2, all_hub);
> -
> -             if (flush_type == 2 && adev->gmc.flush_tlb_needs_extra_type_0)
> -                     kiq->pmf->kiq_invalidate_tlbs(ring, pasid, 0, all_hub);
> -
> -             kiq->pmf->kiq_invalidate_tlbs(ring, pasid, flush_type, all_hub);
> -             r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT);
> -             if (r) {
> -                     amdgpu_ring_undo(ring);
> -                     spin_unlock(&adev->gfx.kiq[inst].ring_lock);
> -                     goto error_unlock_reset;
> -             }
> -
> -             amdgpu_ring_commit(ring);
> -             spin_unlock(&adev->gfx.kiq[inst].ring_lock);
> -
> -             r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
> -
> -             might_sleep();
> -             while (r < 1 && cnt++ < MAX_KIQ_REG_TRY &&
> -                    !amdgpu_reset_pending(adev->reset_domain)) {
> -                     msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
> -                     r = amdgpu_fence_wait_polling(ring, seq,
> MAX_KIQ_REG_WAIT);
> -             }
> -
> -             if (cnt > MAX_KIQ_REG_TRY) {
> -                     dev_err(adev->dev, "timeout waiting for kiq fence\n");
> -                     r = -ETIME;
> -             } else
> -                     r = 0;
>       }
>
>  error_unlock_reset:
> diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> index 4bb10a89ce582..e7c529620199b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> @@ -974,6 +974,8 @@ static int gmc_v10_0_hw_init(struct amdgpu_ip_block
> *ip_block)
>       int r;
>
>       adev->gmc.flush_pasid_uses_kiq = !amdgpu_emu_mode;
> +     if (adev->gmc.flush_pasid_uses_kiq)
> +             adev->gmc.pasid_inv_method =
> AMDGPU_TLB_INV_METHOD_KIQ;
>
>       /* The sequence of these two function calls matters.*/
>       gmc_v10_0_init_golden_registers(adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
> b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
> index acab9f4180da6..a35c84cc7385f 100644
> --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
> @@ -950,6 +950,8 @@ static int gmc_v11_0_hw_init(struct amdgpu_ip_block
> *ip_block)
>       int r;
>
>       adev->gmc.flush_pasid_uses_kiq = !amdgpu_emu_mode;
> +     if (adev->gmc.flush_pasid_uses_kiq)
> +             adev->gmc.pasid_inv_method =
> AMDGPU_TLB_INV_METHOD_KIQ;
>
>       /* The sequence of these two function calls matters.*/
>       gmc_v11_0_init_golden_registers(adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
> b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
> index 3c13a6920171a..317b44412b5a6 100644
> --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
> @@ -2162,6 +2162,8 @@ static int gmc_v9_0_hw_init(struct amdgpu_ip_block
> *ip_block)
>       int i, r;
>
>       adev->gmc.flush_pasid_uses_kiq = true;
> +     if (adev->gmc.flush_pasid_uses_kiq)
> +             adev->gmc.pasid_inv_method =
> AMDGPU_TLB_INV_METHOD_KIQ;
>
>       /* Vega20+XGMI caches PTEs in TC and TLB. Add a heavy-weight TLB
> flush
>        * (type 2), which flushes both. Due to a race condition with
> --
> 2.55.0

Reply via email to