1620f774fSChristian König /*
2620f774fSChristian König * Copyright 2017 Advanced Micro Devices, Inc.
3620f774fSChristian König *
4620f774fSChristian König * Permission is hereby granted, free of charge, to any person obtaining a
5620f774fSChristian König * copy of this software and associated documentation files (the "Software"),
6620f774fSChristian König * to deal in the Software without restriction, including without limitation
7620f774fSChristian König * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8620f774fSChristian König * and/or sell copies of the Software, and to permit persons to whom the
9620f774fSChristian König * Software is furnished to do so, subject to the following conditions:
10620f774fSChristian König *
11620f774fSChristian König * The above copyright notice and this permission notice shall be included in
12620f774fSChristian König * all copies or substantial portions of the Software.
13620f774fSChristian König *
14620f774fSChristian König * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15620f774fSChristian König * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16620f774fSChristian König * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17620f774fSChristian König * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18620f774fSChristian König * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19620f774fSChristian König * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20620f774fSChristian König * OTHER DEALINGS IN THE SOFTWARE.
21620f774fSChristian König *
22620f774fSChristian König */
23620f774fSChristian König #include "amdgpu_ids.h"
24620f774fSChristian König
25620f774fSChristian König #include <linux/idr.h>
26620f774fSChristian König #include <linux/dma-fence-array.h>
27fdf2f6c5SSam Ravnborg
28620f774fSChristian König
29620f774fSChristian König #include "amdgpu.h"
30620f774fSChristian König #include "amdgpu_trace.h"
31620f774fSChristian König
32620f774fSChristian König /*
33620f774fSChristian König * PASID manager
34620f774fSChristian König *
35620f774fSChristian König * PASIDs are global address space identifiers that can be shared
36620f774fSChristian König * between the GPU, an IOMMU and the driver. VMs on different devices
37620f774fSChristian König * may use the same PASID if they share the same address
38620f774fSChristian König * space. Therefore PASIDs are allocated using a global IDA. VMs are
39620f774fSChristian König * looked up from the PASID per amdgpu_device.
40620f774fSChristian König */
41620f774fSChristian König static DEFINE_IDA(amdgpu_pasid_ida);
42620f774fSChristian König
434b5f7550SChristian König /* Helper to free pasid from a fence callback */
444b5f7550SChristian König struct amdgpu_pasid_cb {
454b5f7550SChristian König struct dma_fence_cb cb;
46c7b6bac9SFenghua Yu u32 pasid;
474b5f7550SChristian König };
484b5f7550SChristian König
49620f774fSChristian König /**
50620f774fSChristian König * amdgpu_pasid_alloc - Allocate a PASID
51620f774fSChristian König * @bits: Maximum width of the PASID in bits, must be at least 1
52620f774fSChristian König *
53620f774fSChristian König * Allocates a PASID of the given width while keeping smaller PASIDs
54620f774fSChristian König * available if possible.
55620f774fSChristian König *
56620f774fSChristian König * Returns a positive integer on success. Returns %-EINVAL if bits==0.
57620f774fSChristian König * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
58620f774fSChristian König * memory allocation failure.
59620f774fSChristian König */
amdgpu_pasid_alloc(unsigned int bits)60620f774fSChristian König int amdgpu_pasid_alloc(unsigned int bits)
61620f774fSChristian König {
62620f774fSChristian König int pasid = -EINVAL;
63620f774fSChristian König
64620f774fSChristian König for (bits = min(bits, 31U); bits > 0; bits--) {
658a1f7fddSChristophe JAILLET pasid = ida_alloc_range(&amdgpu_pasid_ida, 1U << (bits - 1),
668a1f7fddSChristophe JAILLET (1U << bits) - 1, GFP_KERNEL);
67620f774fSChristian König if (pasid != -ENOSPC)
68620f774fSChristian König break;
69620f774fSChristian König }
70620f774fSChristian König
71c35ff188SChristian König if (pasid >= 0)
72c35ff188SChristian König trace_amdgpu_pasid_allocated(pasid);
73c35ff188SChristian König
74620f774fSChristian König return pasid;
75620f774fSChristian König }
76620f774fSChristian König
77620f774fSChristian König /**
78620f774fSChristian König * amdgpu_pasid_free - Free a PASID
79620f774fSChristian König * @pasid: PASID to free
80620f774fSChristian König */
amdgpu_pasid_free(u32 pasid)81c7b6bac9SFenghua Yu void amdgpu_pasid_free(u32 pasid)
82620f774fSChristian König {
83c35ff188SChristian König trace_amdgpu_pasid_freed(pasid);
848a1f7fddSChristophe JAILLET ida_free(&amdgpu_pasid_ida, pasid);
85620f774fSChristian König }
86620f774fSChristian König
amdgpu_pasid_free_cb(struct dma_fence * fence,struct dma_fence_cb * _cb)874b5f7550SChristian König static void amdgpu_pasid_free_cb(struct dma_fence *fence,
884b5f7550SChristian König struct dma_fence_cb *_cb)
894b5f7550SChristian König {
904b5f7550SChristian König struct amdgpu_pasid_cb *cb =
914b5f7550SChristian König container_of(_cb, struct amdgpu_pasid_cb, cb);
924b5f7550SChristian König
934b5f7550SChristian König amdgpu_pasid_free(cb->pasid);
944b5f7550SChristian König dma_fence_put(fence);
954b5f7550SChristian König kfree(cb);
964b5f7550SChristian König }
974b5f7550SChristian König
984b5f7550SChristian König /**
994b5f7550SChristian König * amdgpu_pasid_free_delayed - free pasid when fences signal
1004b5f7550SChristian König *
1014b5f7550SChristian König * @resv: reservation object with the fences to wait for
1024b5f7550SChristian König * @pasid: pasid to free
1034b5f7550SChristian König *
1044b5f7550SChristian König * Free the pasid only after all the fences in resv are signaled.
1054b5f7550SChristian König */
amdgpu_pasid_free_delayed(struct dma_resv * resv,u32 pasid)10652791eeeSChristian König void amdgpu_pasid_free_delayed(struct dma_resv *resv,
107c7b6bac9SFenghua Yu u32 pasid)
1084b5f7550SChristian König {
1094b5f7550SChristian König struct amdgpu_pasid_cb *cb;
110ba5f33ccSChristian König struct dma_fence *fence;
1114b5f7550SChristian König int r;
1124b5f7550SChristian König
1130cc848a7SChristian König r = dma_resv_get_singleton(resv, DMA_RESV_USAGE_BOOKKEEP, &fence);
1144b5f7550SChristian König if (r)
1154b5f7550SChristian König goto fallback;
1164b5f7550SChristian König
117ba5f33ccSChristian König if (!fence) {
1184b5f7550SChristian König amdgpu_pasid_free(pasid);
1194b5f7550SChristian König return;
1204b5f7550SChristian König }
1214b5f7550SChristian König
1224b5f7550SChristian König cb = kmalloc(sizeof(*cb), GFP_KERNEL);
1234b5f7550SChristian König if (!cb) {
1244b5f7550SChristian König /* Last resort when we are OOM */
1254b5f7550SChristian König dma_fence_wait(fence, false);
1264b5f7550SChristian König dma_fence_put(fence);
1274b5f7550SChristian König amdgpu_pasid_free(pasid);
1284b5f7550SChristian König } else {
1294b5f7550SChristian König cb->pasid = pasid;
1304b5f7550SChristian König if (dma_fence_add_callback(fence, &cb->cb,
1314b5f7550SChristian König amdgpu_pasid_free_cb))
1324b5f7550SChristian König amdgpu_pasid_free_cb(fence, &cb->cb);
1334b5f7550SChristian König }
1344b5f7550SChristian König
1354b5f7550SChristian König return;
1364b5f7550SChristian König
1374b5f7550SChristian König fallback:
1384b5f7550SChristian König /* Not enough memory for the delayed delete, as last resort
1394b5f7550SChristian König * block for all the fences to complete.
1404b5f7550SChristian König */
1410cc848a7SChristian König dma_resv_wait_timeout(resv, DMA_RESV_USAGE_BOOKKEEP,
1427bc80a54SChristian König false, MAX_SCHEDULE_TIMEOUT);
1434b5f7550SChristian König amdgpu_pasid_free(pasid);
1444b5f7550SChristian König }
1454b5f7550SChristian König
146620f774fSChristian König /*
147620f774fSChristian König * VMID manager
148620f774fSChristian König *
149620f774fSChristian König * VMIDs are a per VMHUB identifier for page tables handling.
150620f774fSChristian König */
151620f774fSChristian König
152620f774fSChristian König /**
153620f774fSChristian König * amdgpu_vmid_had_gpu_reset - check if reset occured since last use
154620f774fSChristian König *
155620f774fSChristian König * @adev: amdgpu_device pointer
156620f774fSChristian König * @id: VMID structure
157620f774fSChristian König *
158620f774fSChristian König * Check if GPU reset occured since last use of the VMID.
159620f774fSChristian König */
amdgpu_vmid_had_gpu_reset(struct amdgpu_device * adev,struct amdgpu_vmid * id)160620f774fSChristian König bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
161620f774fSChristian König struct amdgpu_vmid *id)
162620f774fSChristian König {
163620f774fSChristian König return id->current_gpu_reset_count !=
164620f774fSChristian König atomic_read(&adev->gpu_reset_counter);
165620f774fSChristian König }
166620f774fSChristian König
16756b0989eSChristian König /* Check if we need to switch to another set of resources */
amdgpu_vmid_gds_switch_needed(struct amdgpu_vmid * id,struct amdgpu_job * job)16856b0989eSChristian König static bool amdgpu_vmid_gds_switch_needed(struct amdgpu_vmid *id,
16956b0989eSChristian König struct amdgpu_job *job)
17056b0989eSChristian König {
17156b0989eSChristian König return id->gds_base != job->gds_base ||
17256b0989eSChristian König id->gds_size != job->gds_size ||
17356b0989eSChristian König id->gws_base != job->gws_base ||
17456b0989eSChristian König id->gws_size != job->gws_size ||
17556b0989eSChristian König id->oa_base != job->oa_base ||
17656b0989eSChristian König id->oa_size != job->oa_size;
17756b0989eSChristian König }
17856b0989eSChristian König
17956b0989eSChristian König /* Check if the id is compatible with the job */
amdgpu_vmid_compatible(struct amdgpu_vmid * id,struct amdgpu_job * job)18056b0989eSChristian König static bool amdgpu_vmid_compatible(struct amdgpu_vmid *id,
18156b0989eSChristian König struct amdgpu_job *job)
18256b0989eSChristian König {
18356b0989eSChristian König return id->pd_gpu_addr == job->vm_pd_addr &&
18456b0989eSChristian König !amdgpu_vmid_gds_switch_needed(id, job);
18556b0989eSChristian König }
18656b0989eSChristian König
1873a80e92bSChristian König /**
188c4cd63f9SLee Jones * amdgpu_vmid_grab_idle - grab idle VMID
1893a80e92bSChristian König *
1903a80e92bSChristian König * @ring: ring we want to submit job to
1913a80e92bSChristian König * @idle: resulting idle VMID
192940ca22bSChristian König * @fence: fence to wait for if no id could be grabbed
1933a80e92bSChristian König *
1943a80e92bSChristian König * Try to find an idle VMID, if none is idle add a fence to wait to the sync
1953a80e92bSChristian König * object. Returns -ENOMEM when we are out of memory.
1963a80e92bSChristian König */
amdgpu_vmid_grab_idle(struct amdgpu_ring * ring,struct amdgpu_vmid ** idle,struct dma_fence ** fence)1974d5dc626SYifan Zhang static int amdgpu_vmid_grab_idle(struct amdgpu_ring *ring,
198940ca22bSChristian König struct amdgpu_vmid **idle,
199940ca22bSChristian König struct dma_fence **fence)
2003a80e92bSChristian König {
2013a80e92bSChristian König struct amdgpu_device *adev = ring->adev;
2020530553bSLe Ma unsigned vmhub = ring->vm_hub;
2033a80e92bSChristian König struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
2043a80e92bSChristian König struct dma_fence **fences;
2053a80e92bSChristian König unsigned i;
2063a80e92bSChristian König
207940ca22bSChristian König if (!dma_fence_is_signaled(ring->vmid_wait)) {
208940ca22bSChristian König *fence = dma_fence_get(ring->vmid_wait);
209940ca22bSChristian König return 0;
210940ca22bSChristian König }
2113af81440SChristian König
21216590745SChristian König fences = kmalloc_array(id_mgr->num_ids, sizeof(void *), GFP_NOWAIT);
2133a80e92bSChristian König if (!fences)
2143a80e92bSChristian König return -ENOMEM;
2153a80e92bSChristian König
2163a80e92bSChristian König /* Check if we have an idle VMID */
2173a80e92bSChristian König i = 0;
2183a80e92bSChristian König list_for_each_entry((*idle), &id_mgr->ids_lru, list) {
21920a5f5a9SChristian König /* Don't use per engine and per process VMID at the same time */
22020a5f5a9SChristian König struct amdgpu_ring *r = adev->vm_manager.concurrent_flush ?
22120a5f5a9SChristian König NULL : ring;
22220a5f5a9SChristian König
22320a5f5a9SChristian König fences[i] = amdgpu_sync_peek_fence(&(*idle)->active, r);
2243a80e92bSChristian König if (!fences[i])
2253a80e92bSChristian König break;
2263a80e92bSChristian König ++i;
2273a80e92bSChristian König }
2283a80e92bSChristian König
2293a80e92bSChristian König /* If we can't find a idle VMID to use, wait till one becomes available */
2303a80e92bSChristian König if (&(*idle)->list == &id_mgr->ids_lru) {
2313a80e92bSChristian König u64 fence_context = adev->vm_manager.fence_context + ring->idx;
2323a80e92bSChristian König unsigned seqno = ++adev->vm_manager.seqno[ring->idx];
2333a80e92bSChristian König struct dma_fence_array *array;
2343a80e92bSChristian König unsigned j;
2353a80e92bSChristian König
2363a80e92bSChristian König *idle = NULL;
2373a80e92bSChristian König for (j = 0; j < i; ++j)
2383a80e92bSChristian König dma_fence_get(fences[j]);
2393a80e92bSChristian König
2403a80e92bSChristian König array = dma_fence_array_create(i, fences, fence_context,
2413a80e92bSChristian König seqno, true);
2423a80e92bSChristian König if (!array) {
2433a80e92bSChristian König for (j = 0; j < i; ++j)
2443a80e92bSChristian König dma_fence_put(fences[j]);
2453a80e92bSChristian König kfree(fences);
2463a80e92bSChristian König return -ENOMEM;
2473a80e92bSChristian König }
2483a80e92bSChristian König
249940ca22bSChristian König *fence = dma_fence_get(&array->base);
2503af81440SChristian König dma_fence_put(ring->vmid_wait);
2513af81440SChristian König ring->vmid_wait = &array->base;
252940ca22bSChristian König return 0;
2533a80e92bSChristian König }
2543a80e92bSChristian König kfree(fences);
2553a80e92bSChristian König
2563a80e92bSChristian König return 0;
2573a80e92bSChristian König }
2583a80e92bSChristian König
259cb5372acSChristian König /**
260c4cd63f9SLee Jones * amdgpu_vmid_grab_reserved - try to assign reserved VMID
261cb5372acSChristian König *
262cb5372acSChristian König * @vm: vm to allocate id for
263cb5372acSChristian König * @ring: ring we want to submit job to
264cb5372acSChristian König * @job: job who wants to use the VMID
2658ebc6df6SLee Jones * @id: resulting VMID
266940ca22bSChristian König * @fence: fence to wait for if no id could be grabbed
267cb5372acSChristian König *
268cb5372acSChristian König * Try to assign a reserved VMID.
269cb5372acSChristian König */
amdgpu_vmid_grab_reserved(struct amdgpu_vm * vm,struct amdgpu_ring * ring,struct amdgpu_job * job,struct amdgpu_vmid ** id,struct dma_fence ** fence)270cb5372acSChristian König static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
271620f774fSChristian König struct amdgpu_ring *ring,
27258592a09SChristian König struct amdgpu_job *job,
273940ca22bSChristian König struct amdgpu_vmid **id,
274940ca22bSChristian König struct dma_fence **fence)
275620f774fSChristian König {
276620f774fSChristian König struct amdgpu_device *adev = ring->adev;
2770530553bSLe Ma unsigned vmhub = ring->vm_hub;
278e44a0fe6SChristian König struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
279620f774fSChristian König uint64_t fence_context = adev->fence_context + ring->idx;
280620f774fSChristian König bool needs_flush = vm->use_cpu_for_update;
2815255e146SChristian König uint64_t updates = amdgpu_vm_tlb_seq(vm);
282e997b827SChristian König int r;
283620f774fSChristian König
284e44a0fe6SChristian König *id = id_mgr->reserved;
285eaad0c3aSChristian König if ((*id)->owner != vm->immediate.fence_context ||
28656b0989eSChristian König !amdgpu_vmid_compatible(*id, job) ||
287e997b827SChristian König (*id)->flushed_updates < updates ||
288e997b827SChristian König !(*id)->last_flush ||
28958592a09SChristian König ((*id)->last_flush->context != fence_context &&
290bd22e44aSChristian König !dma_fence_is_signaled((*id)->last_flush)))
291bd22e44aSChristian König needs_flush = true;
292bd22e44aSChristian König
293bd22e44aSChristian König if ((*id)->owner != vm->immediate.fence_context ||
294bd22e44aSChristian König (!adev->vm_manager.concurrent_flush && needs_flush)) {
295cb5372acSChristian König struct dma_fence *tmp;
296cb5372acSChristian König
297a6328c9cSChristian König /* Don't use per engine and per process VMID at the
298a6328c9cSChristian König * same time
299a6328c9cSChristian König */
30020a5f5a9SChristian König if (adev->vm_manager.concurrent_flush)
30120a5f5a9SChristian König ring = NULL;
30220a5f5a9SChristian König
303620f774fSChristian König /* to prevent one context starved by another context */
30458592a09SChristian König (*id)->pd_gpu_addr = 0;
30558592a09SChristian König tmp = amdgpu_sync_peek_fence(&(*id)->active, ring);
306620f774fSChristian König if (tmp) {
30758592a09SChristian König *id = NULL;
308940ca22bSChristian König *fence = dma_fence_get(tmp);
309940ca22bSChristian König return 0;
310620f774fSChristian König }
311a6328c9cSChristian König }
312620f774fSChristian König
313620f774fSChristian König /* Good we can use this VMID. Remember this submission as
314620f774fSChristian König * user of the VMID.
315620f774fSChristian König */
31616590745SChristian König r = amdgpu_sync_fence(&(*id)->active, &job->base.s_fence->finished,
31716590745SChristian König GFP_NOWAIT);
318620f774fSChristian König if (r)
319cb5372acSChristian König return r;
320620f774fSChristian König
321620f774fSChristian König job->vm_needs_flush = needs_flush;
3225f3c40e9SChristian König job->spm_update_needed = true;
323cb5372acSChristian König return 0;
324620f774fSChristian König }
325620f774fSChristian König
326620f774fSChristian König /**
327c4cd63f9SLee Jones * amdgpu_vmid_grab_used - try to reuse a VMID
32825ddf75bSChristian König *
32925ddf75bSChristian König * @vm: vm to allocate id for
33025ddf75bSChristian König * @ring: ring we want to submit job to
33125ddf75bSChristian König * @job: job who wants to use the VMID
33225ddf75bSChristian König * @id: resulting VMID
33325ddf75bSChristian König *
33425ddf75bSChristian König * Try to reuse a VMID for this submission.
33525ddf75bSChristian König */
amdgpu_vmid_grab_used(struct amdgpu_vm * vm,struct amdgpu_ring * ring,struct amdgpu_job * job,struct amdgpu_vmid ** id)33625ddf75bSChristian König static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
33725ddf75bSChristian König struct amdgpu_ring *ring,
33825ddf75bSChristian König struct amdgpu_job *job,
339fc282e9eSTvrtko Ursulin struct amdgpu_vmid **id)
34025ddf75bSChristian König {
34125ddf75bSChristian König struct amdgpu_device *adev = ring->adev;
3420530553bSLe Ma unsigned vmhub = ring->vm_hub;
34325ddf75bSChristian König struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
34425ddf75bSChristian König uint64_t fence_context = adev->fence_context + ring->idx;
3455255e146SChristian König uint64_t updates = amdgpu_vm_tlb_seq(vm);
34625ddf75bSChristian König int r;
34725ddf75bSChristian König
34825ddf75bSChristian König job->vm_needs_flush = vm->use_cpu_for_update;
34925ddf75bSChristian König
35025ddf75bSChristian König /* Check if we can use a VMID already assigned to this VM */
35125ddf75bSChristian König list_for_each_entry_reverse((*id), &id_mgr->ids_lru, list) {
35225ddf75bSChristian König bool needs_flush = vm->use_cpu_for_update;
35325ddf75bSChristian König
35425ddf75bSChristian König /* Check all the prerequisites to using this VMID */
355eaad0c3aSChristian König if ((*id)->owner != vm->immediate.fence_context)
35625ddf75bSChristian König continue;
35725ddf75bSChristian König
35856b0989eSChristian König if (!amdgpu_vmid_compatible(*id, job))
35925ddf75bSChristian König continue;
36025ddf75bSChristian König
36125ddf75bSChristian König if (!(*id)->last_flush ||
36225ddf75bSChristian König ((*id)->last_flush->context != fence_context &&
36325ddf75bSChristian König !dma_fence_is_signaled((*id)->last_flush)))
36425ddf75bSChristian König needs_flush = true;
36525ddf75bSChristian König
366e997b827SChristian König if ((*id)->flushed_updates < updates)
36725ddf75bSChristian König needs_flush = true;
36825ddf75bSChristian König
36920a5f5a9SChristian König if (needs_flush && !adev->vm_manager.concurrent_flush)
37025ddf75bSChristian König continue;
37125ddf75bSChristian König
37225ddf75bSChristian König /* Good, we can use this VMID. Remember this submission as
37325ddf75bSChristian König * user of the VMID.
37425ddf75bSChristian König */
375c5093cddSChristian König r = amdgpu_sync_fence(&(*id)->active,
37616590745SChristian König &job->base.s_fence->finished,
37716590745SChristian König GFP_NOWAIT);
37825ddf75bSChristian König if (r)
37925ddf75bSChristian König return r;
38025ddf75bSChristian König
38125ddf75bSChristian König job->vm_needs_flush |= needs_flush;
38225ddf75bSChristian König return 0;
38325ddf75bSChristian König }
38425ddf75bSChristian König
38525ddf75bSChristian König *id = NULL;
38625ddf75bSChristian König return 0;
38725ddf75bSChristian König }
38825ddf75bSChristian König
38925ddf75bSChristian König /**
390c4cd63f9SLee Jones * amdgpu_vmid_grab - allocate the next free VMID
391620f774fSChristian König *
392620f774fSChristian König * @vm: vm to allocate id for
393620f774fSChristian König * @ring: ring we want to submit job to
394cb5372acSChristian König * @job: job who wants to use the VMID
395940ca22bSChristian König * @fence: fence to wait for if no id could be grabbed
396620f774fSChristian König *
397620f774fSChristian König * Allocate an id for the vm, adding fences to the sync obj as necessary.
398620f774fSChristian König */
amdgpu_vmid_grab(struct amdgpu_vm * vm,struct amdgpu_ring * ring,struct amdgpu_job * job,struct dma_fence ** fence)399620f774fSChristian König int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
400940ca22bSChristian König struct amdgpu_job *job, struct dma_fence **fence)
401620f774fSChristian König {
402620f774fSChristian König struct amdgpu_device *adev = ring->adev;
4030530553bSLe Ma unsigned vmhub = ring->vm_hub;
404620f774fSChristian König struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
405ed024578SHarry Wentland struct amdgpu_vmid *idle = NULL;
406ed024578SHarry Wentland struct amdgpu_vmid *id = NULL;
407620f774fSChristian König int r = 0;
408620f774fSChristian König
409620f774fSChristian König mutex_lock(&id_mgr->lock);
4104d5dc626SYifan Zhang r = amdgpu_vmid_grab_idle(ring, &idle, fence);
4113a80e92bSChristian König if (r || !idle)
412620f774fSChristian König goto error;
413620f774fSChristian König
414*db1e58ecSChristian König if (amdgpu_vmid_uses_reserved(vm, vmhub)) {
415940ca22bSChristian König r = amdgpu_vmid_grab_reserved(vm, ring, job, &id, fence);
41658592a09SChristian König if (r || !id)
41758592a09SChristian König goto error;
41858592a09SChristian König } else {
419fc282e9eSTvrtko Ursulin r = amdgpu_vmid_grab_used(vm, ring, job, &id);
420620f774fSChristian König if (r)
421620f774fSChristian König goto error;
422620f774fSChristian König
42325ddf75bSChristian König if (!id) {
424620f774fSChristian König /* Still no ID to use? Then use the idle one found earlier */
425620f774fSChristian König id = idle;
426620f774fSChristian König
427620f774fSChristian König /* Remember this submission as user of the VMID */
428c5093cddSChristian König r = amdgpu_sync_fence(&id->active,
42916590745SChristian König &job->base.s_fence->finished,
43016590745SChristian König GFP_NOWAIT);
431620f774fSChristian König if (r)
432620f774fSChristian König goto error;
433620f774fSChristian König
434620f774fSChristian König job->vm_needs_flush = true;
43525ddf75bSChristian König }
43625ddf75bSChristian König
43758592a09SChristian König list_move_tail(&id->list, &id_mgr->ids_lru);
43858592a09SChristian König }
43958592a09SChristian König
44056b0989eSChristian König job->gds_switch_needed = amdgpu_vmid_gds_switch_needed(id, job);
44125ddf75bSChristian König if (job->vm_needs_flush) {
44256b0989eSChristian König id->flushed_updates = amdgpu_vm_tlb_seq(vm);
443620f774fSChristian König dma_fence_put(id->last_flush);
444620f774fSChristian König id->last_flush = NULL;
44525ddf75bSChristian König }
446c4f46f22SChristian König job->vmid = id - id_mgr->ids;
4475a4633c4SChristian König job->pasid = vm->pasid;
44856b0989eSChristian König
44956b0989eSChristian König id->gds_base = job->gds_base;
45056b0989eSChristian König id->gds_size = job->gds_size;
45156b0989eSChristian König id->gws_base = job->gws_base;
45256b0989eSChristian König id->gws_size = job->gws_size;
45356b0989eSChristian König id->oa_base = job->oa_base;
45456b0989eSChristian König id->oa_size = job->oa_size;
45556b0989eSChristian König id->pd_gpu_addr = job->vm_pd_addr;
45656b0989eSChristian König id->owner = vm->immediate.fence_context;
45756b0989eSChristian König
458620f774fSChristian König trace_amdgpu_vm_grab_id(vm, ring, job);
459620f774fSChristian König
460620f774fSChristian König error:
461620f774fSChristian König mutex_unlock(&id_mgr->lock);
462620f774fSChristian König return r;
463620f774fSChristian König }
464620f774fSChristian König
465320debcaSChristian König /*
466320debcaSChristian König * amdgpu_vmid_uses_reserved - check if a VM will use a reserved VMID
467320debcaSChristian König * @vm: the VM to check
468320debcaSChristian König * @vmhub: the VMHUB which will be used
469320debcaSChristian König *
470320debcaSChristian König * Returns: True if the VM will use a reserved VMID.
471320debcaSChristian König */
amdgpu_vmid_uses_reserved(struct amdgpu_vm * vm,unsigned int vmhub)472*db1e58ecSChristian König bool amdgpu_vmid_uses_reserved(struct amdgpu_vm *vm, unsigned int vmhub)
473320debcaSChristian König {
474*db1e58ecSChristian König return vm->reserved_vmid[vmhub];
475320debcaSChristian König }
476320debcaSChristian König
amdgpu_vmid_alloc_reserved(struct amdgpu_device * adev,unsigned vmhub)477620f774fSChristian König int amdgpu_vmid_alloc_reserved(struct amdgpu_device *adev,
478620f774fSChristian König unsigned vmhub)
479620f774fSChristian König {
480e44a0fe6SChristian König struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
481620f774fSChristian König
482620f774fSChristian König mutex_lock(&id_mgr->lock);
483620f774fSChristian König
484e44a0fe6SChristian König ++id_mgr->reserved_use_count;
485e44a0fe6SChristian König if (!id_mgr->reserved) {
486e44a0fe6SChristian König struct amdgpu_vmid *id;
487e44a0fe6SChristian König
488e44a0fe6SChristian König id = list_first_entry(&id_mgr->ids_lru, struct amdgpu_vmid,
489e44a0fe6SChristian König list);
490e44a0fe6SChristian König /* Remove from normal round robin handling */
491e44a0fe6SChristian König list_del_init(&id->list);
492e44a0fe6SChristian König id_mgr->reserved = id;
493e44a0fe6SChristian König }
494e44a0fe6SChristian König
495620f774fSChristian König mutex_unlock(&id_mgr->lock);
496e44a0fe6SChristian König return 0;
497620f774fSChristian König }
498620f774fSChristian König
amdgpu_vmid_free_reserved(struct amdgpu_device * adev,unsigned vmhub)499620f774fSChristian König void amdgpu_vmid_free_reserved(struct amdgpu_device *adev,
500620f774fSChristian König unsigned vmhub)
501620f774fSChristian König {
502620f774fSChristian König struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
503620f774fSChristian König
504620f774fSChristian König mutex_lock(&id_mgr->lock);
50580e709eeSChong Li if (!--id_mgr->reserved_use_count) {
506e44a0fe6SChristian König /* give the reserved ID back to normal round robin */
507e44a0fe6SChristian König list_add(&id_mgr->reserved->list, &id_mgr->ids_lru);
5084463b1eeSChristian König id_mgr->reserved = NULL;
509620f774fSChristian König }
51080e709eeSChong Li
511620f774fSChristian König mutex_unlock(&id_mgr->lock);
512620f774fSChristian König }
513620f774fSChristian König
514620f774fSChristian König /**
515620f774fSChristian König * amdgpu_vmid_reset - reset VMID to zero
516620f774fSChristian König *
517620f774fSChristian König * @adev: amdgpu device structure
5188ebc6df6SLee Jones * @vmhub: vmhub type
519c4f46f22SChristian König * @vmid: vmid number to use
520620f774fSChristian König *
521620f774fSChristian König * Reset saved GDW, GWS and OA to force switch on next flush.
522620f774fSChristian König */
amdgpu_vmid_reset(struct amdgpu_device * adev,unsigned vmhub,unsigned vmid)523620f774fSChristian König void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub,
524620f774fSChristian König unsigned vmid)
525620f774fSChristian König {
526620f774fSChristian König struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
527620f774fSChristian König struct amdgpu_vmid *id = &id_mgr->ids[vmid];
528620f774fSChristian König
52910237448SChristian König mutex_lock(&id_mgr->lock);
53010237448SChristian König id->owner = 0;
531620f774fSChristian König id->gds_base = 0;
532620f774fSChristian König id->gds_size = 0;
533620f774fSChristian König id->gws_base = 0;
534620f774fSChristian König id->gws_size = 0;
535620f774fSChristian König id->oa_base = 0;
536620f774fSChristian König id->oa_size = 0;
53710237448SChristian König mutex_unlock(&id_mgr->lock);
538620f774fSChristian König }
539620f774fSChristian König
540620f774fSChristian König /**
541620f774fSChristian König * amdgpu_vmid_reset_all - reset VMID to zero
542620f774fSChristian König *
543620f774fSChristian König * @adev: amdgpu device structure
544620f774fSChristian König *
545620f774fSChristian König * Reset VMID to force flush on next use
546620f774fSChristian König */
amdgpu_vmid_reset_all(struct amdgpu_device * adev)547620f774fSChristian König void amdgpu_vmid_reset_all(struct amdgpu_device *adev)
548620f774fSChristian König {
549620f774fSChristian König unsigned i, j;
550620f774fSChristian König
551620f774fSChristian König for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
552620f774fSChristian König struct amdgpu_vmid_mgr *id_mgr =
553620f774fSChristian König &adev->vm_manager.id_mgr[i];
554620f774fSChristian König
555620f774fSChristian König for (j = 1; j < id_mgr->num_ids; ++j)
556620f774fSChristian König amdgpu_vmid_reset(adev, i, j);
557620f774fSChristian König }
558620f774fSChristian König }
559620f774fSChristian König
560620f774fSChristian König /**
561620f774fSChristian König * amdgpu_vmid_mgr_init - init the VMID manager
562620f774fSChristian König *
563620f774fSChristian König * @adev: amdgpu_device pointer
564620f774fSChristian König *
565620f774fSChristian König * Initialize the VM manager structures
566620f774fSChristian König */
amdgpu_vmid_mgr_init(struct amdgpu_device * adev)567620f774fSChristian König void amdgpu_vmid_mgr_init(struct amdgpu_device *adev)
568620f774fSChristian König {
569620f774fSChristian König unsigned i, j;
570620f774fSChristian König
571620f774fSChristian König for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
572620f774fSChristian König struct amdgpu_vmid_mgr *id_mgr =
573620f774fSChristian König &adev->vm_manager.id_mgr[i];
574620f774fSChristian König
575620f774fSChristian König mutex_init(&id_mgr->lock);
576620f774fSChristian König INIT_LIST_HEAD(&id_mgr->ids_lru);
577e44a0fe6SChristian König id_mgr->reserved_use_count = 0;
578620f774fSChristian König
57940111ec2SFelix Kuehling /* manage only VMIDs not used by KFD */
58040111ec2SFelix Kuehling id_mgr->num_ids = adev->vm_manager.first_kfd_vmid;
58140111ec2SFelix Kuehling
582620f774fSChristian König /* skip over VMID 0, since it is the system VM */
583620f774fSChristian König for (j = 1; j < id_mgr->num_ids; ++j) {
584620f774fSChristian König amdgpu_vmid_reset(adev, i, j);
5853df27645SRex Zhu amdgpu_sync_create(&id_mgr->ids[j].active);
586620f774fSChristian König list_add_tail(&id_mgr->ids[j].list, &id_mgr->ids_lru);
587620f774fSChristian König }
588620f774fSChristian König }
58980e709eeSChong Li /* alloc a default reserved vmid to enforce isolation */
59096595204SSrinivasan Shanmugam for (i = 0; i < (adev->xcp_mgr ? adev->xcp_mgr->num_xcps : 1); i++) {
59196595204SSrinivasan Shanmugam if (adev->enforce_isolation[i])
59296595204SSrinivasan Shanmugam amdgpu_vmid_alloc_reserved(adev, AMDGPU_GFXHUB(i));
59396595204SSrinivasan Shanmugam }
594620f774fSChristian König }
595620f774fSChristian König
596620f774fSChristian König /**
597620f774fSChristian König * amdgpu_vmid_mgr_fini - cleanup VM manager
598620f774fSChristian König *
599620f774fSChristian König * @adev: amdgpu_device pointer
600620f774fSChristian König *
601620f774fSChristian König * Cleanup the VM manager and free resources.
602620f774fSChristian König */
amdgpu_vmid_mgr_fini(struct amdgpu_device * adev)603620f774fSChristian König void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
604620f774fSChristian König {
605620f774fSChristian König unsigned i, j;
606620f774fSChristian König
607620f774fSChristian König for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
608620f774fSChristian König struct amdgpu_vmid_mgr *id_mgr =
609620f774fSChristian König &adev->vm_manager.id_mgr[i];
610620f774fSChristian König
611620f774fSChristian König mutex_destroy(&id_mgr->lock);
612620f774fSChristian König for (j = 0; j < AMDGPU_NUM_VMID; ++j) {
613620f774fSChristian König struct amdgpu_vmid *id = &id_mgr->ids[j];
614620f774fSChristian König
615620f774fSChristian König amdgpu_sync_free(&id->active);
616620f774fSChristian König dma_fence_put(id->last_flush);
617b3cd285fSChristian König dma_fence_put(id->pasid_mapping);
618620f774fSChristian König }
619620f774fSChristian König }
620620f774fSChristian König }
621