diff options
author | Christian König <christian.koenig@amd.com> | 2017-02-14 10:02:52 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2017-03-29 23:53:02 -0400 |
commit | 451bc8eb8fe61ee89ebf44e7ee290ab88bb2b2d5 (patch) | |
tree | 54c06cd17f5ad0b521e0a6391a40ddc035307d0e | |
parent | 0b15f2fc3ca20f10c0a3ab659c923a3f693cf29f (diff) |
drm/amdgpu: fix PRT teardown on VM fini v3
v2: new approach fixing this by registering a fence callback for
all users of the VM on teardown
v3: agd: rebase
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 106 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 |
2 files changed, 82 insertions, 26 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 1f1de2115d7d..7e22c3558b29 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | |||
@@ -1188,22 +1188,31 @@ static void amdgpu_vm_update_prt_state(struct amdgpu_device *adev) | |||
1188 | bool enable; | 1188 | bool enable; |
1189 | 1189 | ||
1190 | spin_lock_irqsave(&adev->vm_manager.prt_lock, flags); | 1190 | spin_lock_irqsave(&adev->vm_manager.prt_lock, flags); |
1191 | enable = !!atomic_read(&adev->vm_manager.num_prt_mappings); | 1191 | enable = !!atomic_read(&adev->vm_manager.num_prt_users); |
1192 | adev->gart.gart_funcs->set_prt(adev, enable); | 1192 | adev->gart.gart_funcs->set_prt(adev, enable); |
1193 | spin_unlock_irqrestore(&adev->vm_manager.prt_lock, flags); | 1193 | spin_unlock_irqrestore(&adev->vm_manager.prt_lock, flags); |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | /** | 1196 | /** |
1197 | * amdgpu_vm_prt_put - add a PRT user | ||
1198 | */ | ||
1199 | static void amdgpu_vm_prt_get(struct amdgpu_device *adev) | ||
1200 | { | ||
1201 | if (atomic_inc_return(&adev->vm_manager.num_prt_users) == 1) | ||
1202 | amdgpu_vm_update_prt_state(adev); | ||
1203 | } | ||
1204 | |||
1205 | /** | ||
1197 | * amdgpu_vm_prt_put - drop a PRT user | 1206 | * amdgpu_vm_prt_put - drop a PRT user |
1198 | */ | 1207 | */ |
1199 | static void amdgpu_vm_prt_put(struct amdgpu_device *adev) | 1208 | static void amdgpu_vm_prt_put(struct amdgpu_device *adev) |
1200 | { | 1209 | { |
1201 | if (atomic_dec_return(&adev->vm_manager.num_prt_mappings) == 0) | 1210 | if (atomic_dec_return(&adev->vm_manager.num_prt_users) == 0) |
1202 | amdgpu_vm_update_prt_state(adev); | 1211 | amdgpu_vm_update_prt_state(adev); |
1203 | } | 1212 | } |
1204 | 1213 | ||
1205 | /** | 1214 | /** |
1206 | * amdgpu_vm_prt - callback for updating the PRT status | 1215 | * amdgpu_vm_prt_cb - callback for updating the PRT status |
1207 | */ | 1216 | */ |
1208 | static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb) | 1217 | static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb) |
1209 | { | 1218 | { |
@@ -1214,6 +1223,29 @@ static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb) | |||
1214 | } | 1223 | } |
1215 | 1224 | ||
1216 | /** | 1225 | /** |
1226 | * amdgpu_vm_add_prt_cb - add callback for updating the PRT status | ||
1227 | */ | ||
1228 | static void amdgpu_vm_add_prt_cb(struct amdgpu_device *adev, | ||
1229 | struct dma_fence *fence) | ||
1230 | { | ||
1231 | struct amdgpu_prt_cb *cb = kmalloc(sizeof(struct amdgpu_prt_cb), | ||
1232 | GFP_KERNEL); | ||
1233 | |||
1234 | if (!cb) { | ||
1235 | /* Last resort when we are OOM */ | ||
1236 | if (fence) | ||
1237 | dma_fence_wait(fence, false); | ||
1238 | |||
1239 | amdgpu_vm_prt_put(cb->adev); | ||
1240 | } else { | ||
1241 | cb->adev = adev; | ||
1242 | if (!fence || dma_fence_add_callback(fence, &cb->cb, | ||
1243 | amdgpu_vm_prt_cb)) | ||
1244 | amdgpu_vm_prt_cb(fence, &cb->cb); | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | /** | ||
1217 | * amdgpu_vm_free_mapping - free a mapping | 1249 | * amdgpu_vm_free_mapping - free a mapping |
1218 | * | 1250 | * |
1219 | * @adev: amdgpu_device pointer | 1251 | * @adev: amdgpu_device pointer |
@@ -1228,24 +1260,47 @@ static void amdgpu_vm_free_mapping(struct amdgpu_device *adev, | |||
1228 | struct amdgpu_bo_va_mapping *mapping, | 1260 | struct amdgpu_bo_va_mapping *mapping, |
1229 | struct dma_fence *fence) | 1261 | struct dma_fence *fence) |
1230 | { | 1262 | { |
1231 | if (mapping->flags & AMDGPU_PTE_PRT) { | 1263 | if (mapping->flags & AMDGPU_PTE_PRT) |
1232 | struct amdgpu_prt_cb *cb = kmalloc(sizeof(struct amdgpu_prt_cb), | 1264 | amdgpu_vm_add_prt_cb(adev, fence); |
1233 | GFP_KERNEL); | 1265 | kfree(mapping); |
1266 | } | ||
1234 | 1267 | ||
1235 | if (!cb) { | 1268 | /** |
1236 | /* Last resort when we are OOM */ | 1269 | * amdgpu_vm_prt_fini - finish all prt mappings |
1237 | if (fence) | 1270 | * |
1238 | dma_fence_wait(fence, false); | 1271 | * @adev: amdgpu_device pointer |
1272 | * @vm: requested vm | ||
1273 | * | ||
1274 | * Register a cleanup callback to disable PRT support after VM dies. | ||
1275 | */ | ||
1276 | static void amdgpu_vm_prt_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | ||
1277 | { | ||
1278 | struct reservation_object *resv = vm->page_directory->tbo.resv; | ||
1279 | struct dma_fence *excl, **shared; | ||
1280 | unsigned i, shared_count; | ||
1281 | int r; | ||
1239 | 1282 | ||
1240 | amdgpu_vm_prt_put(cb->adev); | 1283 | r = reservation_object_get_fences_rcu(resv, &excl, |
1241 | } else { | 1284 | &shared_count, &shared); |
1242 | cb->adev = adev; | 1285 | if (r) { |
1243 | if (!fence || dma_fence_add_callback(fence, &cb->cb, | 1286 | /* Not enough memory to grab the fence list, as last resort |
1244 | amdgpu_vm_prt_cb)) | 1287 | * block for all the fences to complete. |
1245 | amdgpu_vm_prt_cb(fence, &cb->cb); | 1288 | */ |
1246 | } | 1289 | reservation_object_wait_timeout_rcu(resv, true, false, |
1290 | MAX_SCHEDULE_TIMEOUT); | ||
1291 | return; | ||
1247 | } | 1292 | } |
1248 | kfree(mapping); | 1293 | |
1294 | /* Add a callback for each fence in the reservation object */ | ||
1295 | amdgpu_vm_prt_get(adev); | ||
1296 | amdgpu_vm_add_prt_cb(adev, excl); | ||
1297 | |||
1298 | for (i = 0; i < shared_count; ++i) { | ||
1299 | amdgpu_vm_prt_get(adev); | ||
1300 | amdgpu_vm_add_prt_cb(adev, shared[i]); | ||
1301 | } | ||
1302 | |||
1303 | kfree(shared); | ||
1249 | } | 1304 | } |
1250 | 1305 | ||
1251 | /** | 1306 | /** |
@@ -1395,8 +1450,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, | |||
1395 | if (!adev->gart.gart_funcs->set_prt) | 1450 | if (!adev->gart.gart_funcs->set_prt) |
1396 | return -EINVAL; | 1451 | return -EINVAL; |
1397 | 1452 | ||
1398 | if (atomic_inc_return(&adev->vm_manager.num_prt_mappings) == 1) | 1453 | amdgpu_vm_prt_get(adev); |
1399 | amdgpu_vm_update_prt_state(adev); | ||
1400 | } | 1454 | } |
1401 | 1455 | ||
1402 | /* make sure object fit at this offset */ | 1456 | /* make sure object fit at this offset */ |
@@ -1699,6 +1753,7 @@ err: | |||
1699 | void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | 1753 | void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) |
1700 | { | 1754 | { |
1701 | struct amdgpu_bo_va_mapping *mapping, *tmp; | 1755 | struct amdgpu_bo_va_mapping *mapping, *tmp; |
1756 | bool prt_fini_called = false; | ||
1702 | int i; | 1757 | int i; |
1703 | 1758 | ||
1704 | amd_sched_entity_fini(vm->entity.sched, &vm->entity); | 1759 | amd_sched_entity_fini(vm->entity.sched, &vm->entity); |
@@ -1712,13 +1767,14 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
1712 | kfree(mapping); | 1767 | kfree(mapping); |
1713 | } | 1768 | } |
1714 | list_for_each_entry_safe(mapping, tmp, &vm->freed, list) { | 1769 | list_for_each_entry_safe(mapping, tmp, &vm->freed, list) { |
1715 | if (mapping->flags & AMDGPU_PTE_PRT) | 1770 | if (mapping->flags & AMDGPU_PTE_PRT && !prt_fini_called) { |
1716 | continue; | 1771 | amdgpu_vm_prt_fini(adev, vm); |
1772 | prt_fini_called = true; | ||
1773 | } | ||
1717 | 1774 | ||
1718 | list_del(&mapping->list); | 1775 | list_del(&mapping->list); |
1719 | kfree(mapping); | 1776 | amdgpu_vm_free_mapping(adev, vm, mapping, NULL); |
1720 | } | 1777 | } |
1721 | amdgpu_vm_clear_freed(adev, vm); | ||
1722 | 1778 | ||
1723 | for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) { | 1779 | for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) { |
1724 | struct amdgpu_bo *pt = vm->page_tables[i].bo; | 1780 | struct amdgpu_bo *pt = vm->page_tables[i].bo; |
@@ -1765,7 +1821,7 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev) | |||
1765 | atomic_set(&adev->vm_manager.vm_pte_next_ring, 0); | 1821 | atomic_set(&adev->vm_manager.vm_pte_next_ring, 0); |
1766 | atomic64_set(&adev->vm_manager.client_counter, 0); | 1822 | atomic64_set(&adev->vm_manager.client_counter, 0); |
1767 | spin_lock_init(&adev->vm_manager.prt_lock); | 1823 | spin_lock_init(&adev->vm_manager.prt_lock); |
1768 | atomic_set(&adev->vm_manager.num_prt_mappings, 0); | 1824 | atomic_set(&adev->vm_manager.num_prt_users, 0); |
1769 | } | 1825 | } |
1770 | 1826 | ||
1771 | /** | 1827 | /** |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 1dc5c1064452..57eaf71a5b1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | |||
@@ -164,7 +164,7 @@ struct amdgpu_vm_manager { | |||
164 | 164 | ||
165 | /* partial resident texture handling */ | 165 | /* partial resident texture handling */ |
166 | spinlock_t prt_lock; | 166 | spinlock_t prt_lock; |
167 | atomic_t num_prt_mappings; | 167 | atomic_t num_prt_users; |
168 | }; | 168 | }; |
169 | 169 | ||
170 | void amdgpu_vm_manager_init(struct amdgpu_device *adev); | 170 | void amdgpu_vm_manager_init(struct amdgpu_device *adev); |