[PATCH 21/30] drm/amdgpu/gmc: rework pasid flushing
Alex Deucher <[email protected]>
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
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); + + 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 13423258d33ed..e9e5a1e183231 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -2181,6 +2181,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