Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdgpu: Attach exclusive fence to prime exported bo's. (v5)

External clients which import our bo's wait only
for exclusive dmabuf-fences, not on shared ones,
ditto for bo's which we import from external
providers and write to.

Therefore attach exclusive fences on prime shared buffers
if our exported buffer gets imported by an external
client, or if we import a buffer from an external
exporter.

See discussion in thread:
https://lists.freedesktop.org/archives/dri-devel/2016-October/122370.html

Prime export tested on Intel iGPU + AMD Tonga dGPU as
DRI3/Present Prime render offload, and with the Tonga
standalone as primary gpu.

v2: Add a wait for all shared fences before prime export,
as suggested by Christian Koenig.

v3: - Mark buffer prime_exported in amdgpu_gem_prime_pin,
so we only use the exclusive fence when exporting a
bo to external clients like a separate iGPU, but not
when exporting/importing from/to ourselves as part of
regular DRI3 fd passing.

- Propagate failure of reservation_object_wait_rcu back
to caller.

v4: - Switch to a prime_shared_count counter instead of a
flag, which gets in/decremented on prime_pin/unpin, so
we can switch back to shared fences if all clients
detach from our exported bo.

- Also switch to exclusive fence for prime imported bo's.

v5: - Drop lret, instead use int ret -> long ret, as proposed
by Christian.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=95472
Tested-by: Mike Lothian <mike@fireburn.co.uk> (v1)
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Christian König <christian.koenig@amd.com>.
Cc: Christian König <christian.koenig@amd.com>
Cc: Michel Dänzer <michel.daenzer@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org

authored by

Mario Kleiner and committed by
Alex Deucher
8e94a46c e2384535

+21 -2
+1
drivers/gpu/drm/amd/amdgpu/amdgpu.h
··· 459 459 u64 metadata_flags; 460 460 void *metadata; 461 461 u32 metadata_size; 462 + unsigned prime_shared_count; 462 463 /* list of all virtual address to which this bo 463 464 * is associated to 464 465 */
+1 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
··· 132 132 entry->priority = min(info[i].bo_priority, 133 133 AMDGPU_BO_LIST_MAX_PRIORITY); 134 134 entry->tv.bo = &entry->robj->tbo; 135 - entry->tv.shared = true; 135 + entry->tv.shared = !entry->robj->prime_shared_count; 136 136 137 137 if (entry->robj->prefered_domains == AMDGPU_GEM_DOMAIN_GDS) 138 138 gds_obj = entry->robj;
+19 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
··· 74 74 if (ret) 75 75 return ERR_PTR(ret); 76 76 77 + bo->prime_shared_count = 1; 77 78 return &bo->gem_base; 78 79 } 79 80 80 81 int amdgpu_gem_prime_pin(struct drm_gem_object *obj) 81 82 { 82 83 struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); 83 - int ret = 0; 84 + long ret = 0; 84 85 85 86 ret = amdgpu_bo_reserve(bo, false); 86 87 if (unlikely(ret != 0)) 87 88 return ret; 88 89 90 + /* 91 + * Wait for all shared fences to complete before we switch to future 92 + * use of exclusive fence on this prime shared bo. 93 + */ 94 + ret = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, false, 95 + MAX_SCHEDULE_TIMEOUT); 96 + if (unlikely(ret < 0)) { 97 + DRM_DEBUG_PRIME("Fence wait failed: %li\n", ret); 98 + amdgpu_bo_unreserve(bo); 99 + return ret; 100 + } 101 + 89 102 /* pin buffer into GTT */ 90 103 ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL); 104 + if (likely(ret == 0)) 105 + bo->prime_shared_count++; 106 + 91 107 amdgpu_bo_unreserve(bo); 92 108 return ret; 93 109 } ··· 118 102 return; 119 103 120 104 amdgpu_bo_unpin(bo); 105 + if (bo->prime_shared_count) 106 + bo->prime_shared_count--; 121 107 amdgpu_bo_unreserve(bo); 122 108 } 123 109