aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2017-01-30 05:09:31 -0500
committerAlex Deucher <alexander.deucher@amd.com>2017-03-29 23:52:56 -0400
commit284710fa6c3a5fddbc0f8c6b3a07861a312c18d2 (patch)
tree8e0b7dd3c8485a308e6066e548f1548fd72feae5
parenta5f6b5b1e89067d3de30ae04693f96189cc05aec (diff)
drm/amdgpu: add basic PRT support (v2)
Future hardware generations can handle PRT flags on a per page basis, but current hardware can only turn it on globally. Add the basic handling for both, a global callback to enable/disable triggered by setting a per mapping flag. v2: agd: rebase fixes 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.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c101
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h6
3 files changed, 98 insertions, 11 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index c1b913541739..618f12884eed 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -294,6 +294,8 @@ struct amdgpu_gart_funcs {
294 uint32_t gpu_page_idx, /* pte/pde to update */ 294 uint32_t gpu_page_idx, /* pte/pde to update */
295 uint64_t addr, /* addr to write into pte/pde */ 295 uint64_t addr, /* addr to write into pte/pde */
296 uint32_t flags); /* access flags */ 296 uint32_t flags); /* access flags */
297 /* enable/disable PRT support */
298 void (*set_prt)(struct amdgpu_device *adev, bool enable);
297}; 299};
298 300
299/* provided by the ih block */ 301/* provided by the ih block */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index f922e4356758..fa06b2a4645f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -69,6 +69,12 @@ struct amdgpu_pte_update_params {
69 bool shadow; 69 bool shadow;
70}; 70};
71 71
72/* Helper to disable partial resident texture feature from a fence callback */
73struct amdgpu_prt_cb {
74 struct amdgpu_device *adev;
75 struct dma_fence_cb cb;
76};
77
72/** 78/**
73 * amdgpu_vm_num_pde - return the number of page directory entries 79 * amdgpu_vm_num_pde - return the number of page directory entries
74 * 80 *
@@ -989,11 +995,8 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
989 goto error_free; 995 goto error_free;
990 996
991 amdgpu_bo_fence(vm->page_directory, f, true); 997 amdgpu_bo_fence(vm->page_directory, f, true);
992 if (fence) { 998 dma_fence_put(*fence);
993 dma_fence_put(*fence); 999 *fence = f;
994 *fence = dma_fence_get(f);
995 }
996 dma_fence_put(f);
997 return 0; 1000 return 0;
998 1001
999error_free: 1002error_free:
@@ -1177,6 +1180,61 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev,
1177} 1180}
1178 1181
1179/** 1182/**
1183 * amdgpu_vm_update_prt_state - update the global PRT state
1184 */
1185static void amdgpu_vm_update_prt_state(struct amdgpu_device *adev)
1186{
1187 unsigned long flags;
1188 bool enable;
1189
1190 spin_lock_irqsave(&adev->vm_manager.prt_lock, flags);
1191 enable = !!atomic_read(&adev->vm_manager.num_prt_mappings);
1192 adev->gart.gart_funcs->set_prt(adev, enable);
1193 spin_unlock_irqrestore(&adev->vm_manager.prt_lock, flags);
1194}
1195
1196/**
1197 * amdgpu_vm_prt - callback for updating the PRT status
1198 */
1199static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb)
1200{
1201 struct amdgpu_prt_cb *cb = container_of(_cb, struct amdgpu_prt_cb, cb);
1202
1203 amdgpu_vm_update_prt_state(cb->adev);
1204 kfree(cb);
1205}
1206
1207/**
1208 * amdgpu_vm_free_mapping - free a mapping
1209 *
1210 * @adev: amdgpu_device pointer
1211 * @vm: requested vm
1212 * @mapping: mapping to be freed
1213 * @fence: fence of the unmap operation
1214 *
1215 * Free a mapping and make sure we decrease the PRT usage count if applicable.
1216 */
1217static void amdgpu_vm_free_mapping(struct amdgpu_device *adev,
1218 struct amdgpu_vm *vm,
1219 struct amdgpu_bo_va_mapping *mapping,
1220 struct dma_fence *fence)
1221{
1222 if ((mapping->flags & AMDGPU_PTE_PRT) &&
1223 atomic_dec_return(&adev->vm_manager.num_prt_mappings) == 0) {
1224 struct amdgpu_prt_cb *cb = kmalloc(sizeof(struct amdgpu_prt_cb),
1225 GFP_KERNEL);
1226
1227 cb->adev = adev;
1228 if (!fence || dma_fence_add_callback(fence, &cb->cb,
1229 amdgpu_vm_prt_cb)) {
1230 amdgpu_vm_update_prt_state(adev);
1231 kfree(cb);
1232 }
1233 }
1234 kfree(mapping);
1235}
1236
1237/**
1180 * amdgpu_vm_clear_freed - clear freed BOs in the PT 1238 * amdgpu_vm_clear_freed - clear freed BOs in the PT
1181 * 1239 *
1182 * @adev: amdgpu_device pointer 1240 * @adev: amdgpu_device pointer
@@ -1191,6 +1249,7 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
1191 struct amdgpu_vm *vm) 1249 struct amdgpu_vm *vm)
1192{ 1250{
1193 struct amdgpu_bo_va_mapping *mapping; 1251 struct amdgpu_bo_va_mapping *mapping;
1252 struct dma_fence *fence = NULL;
1194 int r; 1253 int r;
1195 1254
1196 while (!list_empty(&vm->freed)) { 1255 while (!list_empty(&vm->freed)) {
@@ -1199,12 +1258,15 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
1199 list_del(&mapping->list); 1258 list_del(&mapping->list);
1200 1259
1201 r = amdgpu_vm_bo_split_mapping(adev, NULL, 0, NULL, vm, mapping, 1260 r = amdgpu_vm_bo_split_mapping(adev, NULL, 0, NULL, vm, mapping,
1202 0, 0, NULL); 1261 0, 0, &fence);
1203 kfree(mapping); 1262 amdgpu_vm_free_mapping(adev, vm, mapping, fence);
1204 if (r) 1263 if (r) {
1264 dma_fence_put(fence);
1205 return r; 1265 return r;
1266 }
1206 1267
1207 } 1268 }
1269 dma_fence_put(fence);
1208 return 0; 1270 return 0;
1209 1271
1210} 1272}
@@ -1314,6 +1376,15 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
1314 size == 0 || size & AMDGPU_GPU_PAGE_MASK) 1376 size == 0 || size & AMDGPU_GPU_PAGE_MASK)
1315 return -EINVAL; 1377 return -EINVAL;
1316 1378
1379 if (flags & AMDGPU_PTE_PRT) {
1380 /* Check if we have PRT hardware support */
1381 if (!adev->gart.gart_funcs->set_prt)
1382 return -EINVAL;
1383
1384 if (atomic_inc_return(&adev->vm_manager.num_prt_mappings) == 1)
1385 amdgpu_vm_update_prt_state(adev);
1386 }
1387
1317 /* make sure object fit at this offset */ 1388 /* make sure object fit at this offset */
1318 eaddr = saddr + size - 1; 1389 eaddr = saddr + size - 1;
1319 if (saddr >= eaddr || 1390 if (saddr >= eaddr ||
@@ -1400,7 +1471,7 @@ error_free:
1400 list_del(&mapping->list); 1471 list_del(&mapping->list);
1401 interval_tree_remove(&mapping->it, &vm->va); 1472 interval_tree_remove(&mapping->it, &vm->va);
1402 trace_amdgpu_vm_bo_unmap(bo_va, mapping); 1473 trace_amdgpu_vm_bo_unmap(bo_va, mapping);
1403 kfree(mapping); 1474 amdgpu_vm_free_mapping(adev, vm, mapping, NULL);
1404 1475
1405error: 1476error:
1406 return r; 1477 return r;
@@ -1452,7 +1523,8 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
1452 if (valid) 1523 if (valid)
1453 list_add(&mapping->list, &vm->freed); 1524 list_add(&mapping->list, &vm->freed);
1454 else 1525 else
1455 kfree(mapping); 1526 amdgpu_vm_free_mapping(adev, vm, mapping,
1527 bo_va->last_pt_update);
1456 1528
1457 return 0; 1529 return 0;
1458} 1530}
@@ -1488,7 +1560,8 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
1488 list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) { 1560 list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) {
1489 list_del(&mapping->list); 1561 list_del(&mapping->list);
1490 interval_tree_remove(&mapping->it, &vm->va); 1562 interval_tree_remove(&mapping->it, &vm->va);
1491 kfree(mapping); 1563 amdgpu_vm_free_mapping(adev, vm, mapping,
1564 bo_va->last_pt_update);
1492 } 1565 }
1493 1566
1494 dma_fence_put(bo_va->last_pt_update); 1567 dma_fence_put(bo_va->last_pt_update);
@@ -1625,9 +1698,13 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
1625 kfree(mapping); 1698 kfree(mapping);
1626 } 1699 }
1627 list_for_each_entry_safe(mapping, tmp, &vm->freed, list) { 1700 list_for_each_entry_safe(mapping, tmp, &vm->freed, list) {
1701 if (mapping->flags & AMDGPU_PTE_PRT)
1702 continue;
1703
1628 list_del(&mapping->list); 1704 list_del(&mapping->list);
1629 kfree(mapping); 1705 kfree(mapping);
1630 } 1706 }
1707 amdgpu_vm_clear_freed(adev, vm);
1631 1708
1632 for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) { 1709 for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) {
1633 struct amdgpu_bo *pt = vm->page_tables[i].bo; 1710 struct amdgpu_bo *pt = vm->page_tables[i].bo;
@@ -1673,6 +1750,8 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev)
1673 1750
1674 atomic_set(&adev->vm_manager.vm_pte_next_ring, 0); 1751 atomic_set(&adev->vm_manager.vm_pte_next_ring, 0);
1675 atomic64_set(&adev->vm_manager.client_counter, 0); 1752 atomic64_set(&adev->vm_manager.client_counter, 0);
1753 spin_lock_init(&adev->vm_manager.prt_lock);
1754 atomic_set(&adev->vm_manager.num_prt_mappings, 0);
1676} 1755}
1677 1756
1678/** 1757/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 18c72c0b478d..f90e1c8daf01 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -65,6 +65,8 @@ struct amdgpu_bo_list_entry;
65 65
66#define AMDGPU_PTE_FRAG(x) ((x & 0x1f) << 7) 66#define AMDGPU_PTE_FRAG(x) ((x & 0x1f) << 7)
67 67
68#define AMDGPU_PTE_PRT (1UL << 63)
69
68/* How to programm VM fault handling */ 70/* How to programm VM fault handling */
69#define AMDGPU_VM_FAULT_STOP_NEVER 0 71#define AMDGPU_VM_FAULT_STOP_NEVER 0
70#define AMDGPU_VM_FAULT_STOP_FIRST 1 72#define AMDGPU_VM_FAULT_STOP_FIRST 1
@@ -159,6 +161,10 @@ struct amdgpu_vm_manager {
159 atomic_t vm_pte_next_ring; 161 atomic_t vm_pte_next_ring;
160 /* client id counter */ 162 /* client id counter */
161 atomic64_t client_counter; 163 atomic64_t client_counter;
164
165 /* partial resident texture handling */
166 spinlock_t prt_lock;
167 atomic_t num_prt_mappings;
162}; 168};
163 169
164void amdgpu_vm_manager_init(struct amdgpu_device *adev); 170void amdgpu_vm_manager_init(struct amdgpu_device *adev);