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

drm/xe: Convert multiple bind ops into single job

This aligns with the uAPI of an array of binds or single bind that
results in multiple GPUVA ops to be considered a single atomic
operations.

The design is roughly:
- xe_vma_ops is a list of xe_vma_op (GPUVA op)
- each xe_vma_op resolves to 0-3 PT ops
- xe_vma_ops creates a single job
- if at any point during binding a failure occurs, xe_vma_ops contains
the information necessary unwind the PT and VMA (GPUVA) state

v2:
- add missing dma-resv slot reservation (CI, testing)
v4:
- Fix TLB invalidation (Paulo)
- Add missing xe_sched_job_last_fence_add/test_dep check (Inspection)
v5:
- Invert i, j usage (Matthew Auld)
- Add helper to test and add job dep (Matthew Auld)
- Return on anything but -ETIME for cpu bind (Matthew Auld)
- Return -ENOBUFS if suballoc of BB fails due to size (Matthew Auld)
- s/do/Do (Matthew Auld)
- Add missing comma (Matthew Auld)
- Do not assign return value to xe_range_fence_insert (Matthew Auld)
v6:
- s/0x1ff/MAX_PTE_PER_SDI (Matthew Auld, CI)
- Check to large of SA in Xe to avoid triggering WARN (Matthew Auld)
- Fix checkpatch issues
v7:
- Rebase
- Support more than 510 PTEs updates in a bind job (Paulo, mesa testing)
v8:
- Rebase

Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240704041652.272920-5-matthew.brost@intel.com

+1076 -1038
+2
drivers/gpu/drm/xe/xe_bo_types.h
··· 58 58 #endif 59 59 /** @freed: List node for delayed put. */ 60 60 struct llist_node freed; 61 + /** @update_index: Update index if PT BO */ 62 + int update_index; 61 63 /** @created: Whether the bo has passed initial creation */ 62 64 bool created; 63 65
+164 -165
drivers/gpu/drm/xe/xe_migrate.c
··· 1125 1125 } 1126 1126 1127 1127 static void write_pgtable(struct xe_tile *tile, struct xe_bb *bb, u64 ppgtt_ofs, 1128 + const struct xe_vm_pgtable_update_op *pt_op, 1128 1129 const struct xe_vm_pgtable_update *update, 1129 1130 struct xe_migrate_pt_update *pt_update) 1130 1131 { ··· 1160 1159 bb->cs[bb->len++] = MI_STORE_DATA_IMM | MI_SDI_NUM_QW(chunk); 1161 1160 bb->cs[bb->len++] = lower_32_bits(addr); 1162 1161 bb->cs[bb->len++] = upper_32_bits(addr); 1163 - ops->populate(pt_update, tile, NULL, bb->cs + bb->len, ofs, chunk, 1164 - update); 1162 + if (pt_op->bind) 1163 + ops->populate(pt_update, tile, NULL, bb->cs + bb->len, 1164 + ofs, chunk, update); 1165 + else 1166 + ops->clear(pt_update, tile, NULL, bb->cs + bb->len, 1167 + ofs, chunk, update); 1165 1168 1166 1169 bb->len += chunk * 2; 1167 1170 ofs += chunk; ··· 1190 1185 1191 1186 static struct dma_fence * 1192 1187 xe_migrate_update_pgtables_cpu(struct xe_migrate *m, 1193 - struct xe_vm *vm, struct xe_bo *bo, 1194 - const struct xe_vm_pgtable_update *updates, 1195 - u32 num_updates, bool wait_vm, 1196 1188 struct xe_migrate_pt_update *pt_update) 1197 1189 { 1198 1190 XE_TEST_DECLARE(struct migrate_test_params *test = 1199 1191 to_migrate_test_params 1200 1192 (xe_cur_kunit_priv(XE_TEST_LIVE_MIGRATE));) 1201 1193 const struct xe_migrate_pt_update_ops *ops = pt_update->ops; 1202 - struct dma_fence *fence; 1194 + struct xe_vm *vm = pt_update->vops->vm; 1195 + struct xe_vm_pgtable_update_ops *pt_update_ops = 1196 + &pt_update->vops->pt_update_ops[pt_update->tile_id]; 1203 1197 int err; 1204 - u32 i; 1198 + u32 i, j; 1205 1199 1206 1200 if (XE_TEST_ONLY(test && test->force_gpu)) 1207 - return ERR_PTR(-ETIME); 1208 - 1209 - if (bo && !dma_resv_test_signaled(bo->ttm.base.resv, 1210 - DMA_RESV_USAGE_KERNEL)) 1211 - return ERR_PTR(-ETIME); 1212 - 1213 - if (wait_vm && !dma_resv_test_signaled(xe_vm_resv(vm), 1214 - DMA_RESV_USAGE_BOOKKEEP)) 1215 1201 return ERR_PTR(-ETIME); 1216 1202 1217 1203 if (ops->pre_commit) { ··· 1211 1215 if (err) 1212 1216 return ERR_PTR(err); 1213 1217 } 1214 - for (i = 0; i < num_updates; i++) { 1215 - const struct xe_vm_pgtable_update *update = &updates[i]; 1216 1218 1217 - ops->populate(pt_update, m->tile, &update->pt_bo->vmap, NULL, 1218 - update->ofs, update->qwords, update); 1219 - } 1219 + for (i = 0; i < pt_update_ops->num_ops; ++i) { 1220 + const struct xe_vm_pgtable_update_op *pt_op = 1221 + &pt_update_ops->ops[i]; 1220 1222 1221 - if (vm) { 1222 - trace_xe_vm_cpu_bind(vm); 1223 - xe_device_wmb(vm->xe); 1224 - } 1223 + for (j = 0; j < pt_op->num_entries; j++) { 1224 + const struct xe_vm_pgtable_update *update = 1225 + &pt_op->entries[j]; 1225 1226 1226 - fence = dma_fence_get_stub(); 1227 - 1228 - return fence; 1229 - } 1230 - 1231 - static bool no_in_syncs(struct xe_vm *vm, struct xe_exec_queue *q, 1232 - struct xe_sync_entry *syncs, u32 num_syncs) 1233 - { 1234 - struct dma_fence *fence; 1235 - int i; 1236 - 1237 - for (i = 0; i < num_syncs; i++) { 1238 - fence = syncs[i].fence; 1239 - 1240 - if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, 1241 - &fence->flags)) 1242 - return false; 1243 - } 1244 - if (q) { 1245 - fence = xe_exec_queue_last_fence_get(q, vm); 1246 - if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { 1247 - dma_fence_put(fence); 1248 - return false; 1227 + if (pt_op->bind) 1228 + ops->populate(pt_update, m->tile, 1229 + &update->pt_bo->vmap, NULL, 1230 + update->ofs, update->qwords, 1231 + update); 1232 + else 1233 + ops->clear(pt_update, m->tile, 1234 + &update->pt_bo->vmap, NULL, 1235 + update->ofs, update->qwords, update); 1249 1236 } 1250 - dma_fence_put(fence); 1251 1237 } 1252 1238 1253 - return true; 1239 + trace_xe_vm_cpu_bind(vm); 1240 + xe_device_wmb(vm->xe); 1241 + 1242 + return dma_fence_get_stub(); 1254 1243 } 1255 1244 1256 - /** 1257 - * xe_migrate_update_pgtables() - Pipelined page-table update 1258 - * @m: The migrate context. 1259 - * @vm: The vm we'll be updating. 1260 - * @bo: The bo whose dma-resv we will await before updating, or NULL if userptr. 1261 - * @q: The exec queue to be used for the update or NULL if the default 1262 - * migration engine is to be used. 1263 - * @updates: An array of update descriptors. 1264 - * @num_updates: Number of descriptors in @updates. 1265 - * @syncs: Array of xe_sync_entry to await before updating. Note that waits 1266 - * will block the engine timeline. 1267 - * @num_syncs: Number of entries in @syncs. 1268 - * @pt_update: Pointer to a struct xe_migrate_pt_update, which contains 1269 - * pointers to callback functions and, if subclassed, private arguments to 1270 - * those. 1271 - * 1272 - * Perform a pipelined page-table update. The update descriptors are typically 1273 - * built under the same lock critical section as a call to this function. If 1274 - * using the default engine for the updates, they will be performed in the 1275 - * order they grab the job_mutex. If different engines are used, external 1276 - * synchronization is needed for overlapping updates to maintain page-table 1277 - * consistency. Note that the meaing of "overlapping" is that the updates 1278 - * touch the same page-table, which might be a higher-level page-directory. 1279 - * If no pipelining is needed, then updates may be performed by the cpu. 1280 - * 1281 - * Return: A dma_fence that, when signaled, indicates the update completion. 1282 - */ 1283 - struct dma_fence * 1284 - xe_migrate_update_pgtables(struct xe_migrate *m, 1285 - struct xe_vm *vm, 1286 - struct xe_bo *bo, 1287 - struct xe_exec_queue *q, 1288 - const struct xe_vm_pgtable_update *updates, 1289 - u32 num_updates, 1290 - struct xe_sync_entry *syncs, u32 num_syncs, 1291 - struct xe_migrate_pt_update *pt_update) 1245 + static struct dma_fence * 1246 + __xe_migrate_update_pgtables(struct xe_migrate *m, 1247 + struct xe_migrate_pt_update *pt_update, 1248 + struct xe_vm_pgtable_update_ops *pt_update_ops) 1292 1249 { 1293 1250 const struct xe_migrate_pt_update_ops *ops = pt_update->ops; 1294 1251 struct xe_tile *tile = m->tile; ··· 1250 1301 struct xe_sched_job *job; 1251 1302 struct dma_fence *fence; 1252 1303 struct drm_suballoc *sa_bo = NULL; 1253 - struct xe_vma *vma = pt_update->vma; 1254 1304 struct xe_bb *bb; 1255 - u32 i, batch_size, ppgtt_ofs, update_idx, page_ofs = 0; 1305 + u32 i, j, batch_size = 0, ppgtt_ofs, update_idx, page_ofs = 0; 1306 + u32 num_updates = 0, current_update = 0; 1256 1307 u64 addr; 1257 1308 int err = 0; 1258 - bool usm = !q && xe->info.has_usm; 1259 - bool first_munmap_rebind = vma && 1260 - vma->gpuva.flags & XE_VMA_FIRST_REBIND; 1261 - struct xe_exec_queue *q_override = !q ? m->q : q; 1262 - u16 pat_index = xe->pat.idx[XE_CACHE_WB]; 1309 + bool is_migrate = pt_update_ops->q == m->q; 1310 + bool usm = is_migrate && xe->info.has_usm; 1263 1311 1264 - /* Use the CPU if no in syncs and engine is idle */ 1265 - if (no_in_syncs(vm, q, syncs, num_syncs) && xe_exec_queue_is_idle(q_override)) { 1266 - fence = xe_migrate_update_pgtables_cpu(m, vm, bo, updates, 1267 - num_updates, 1268 - first_munmap_rebind, 1269 - pt_update); 1270 - if (!IS_ERR(fence) || fence == ERR_PTR(-EAGAIN)) 1271 - return fence; 1312 + for (i = 0; i < pt_update_ops->num_ops; ++i) { 1313 + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[i]; 1314 + struct xe_vm_pgtable_update *updates = pt_op->entries; 1315 + 1316 + num_updates += pt_op->num_entries; 1317 + for (j = 0; j < pt_op->num_entries; ++j) { 1318 + u32 num_cmds = DIV_ROUND_UP(updates[j].qwords, 1319 + MAX_PTE_PER_SDI); 1320 + 1321 + /* align noop + MI_STORE_DATA_IMM cmd prefix */ 1322 + batch_size += 4 * num_cmds + updates[j].qwords * 2; 1323 + } 1272 1324 } 1273 1325 1274 1326 /* fixed + PTE entries */ 1275 1327 if (IS_DGFX(xe)) 1276 - batch_size = 2; 1328 + batch_size += 2; 1277 1329 else 1278 - batch_size = 6 + num_updates * 2; 1330 + batch_size += 6 * (num_updates / MAX_PTE_PER_SDI + 1) + 1331 + num_updates * 2; 1279 1332 1280 - for (i = 0; i < num_updates; i++) { 1281 - u32 num_cmds = DIV_ROUND_UP(updates[i].qwords, MAX_PTE_PER_SDI); 1282 - 1283 - /* align noop + MI_STORE_DATA_IMM cmd prefix */ 1284 - batch_size += 4 * num_cmds + updates[i].qwords * 2; 1285 - } 1286 - 1287 - /* 1288 - * XXX: Create temp bo to copy from, if batch_size becomes too big? 1289 - * 1290 - * Worst case: Sum(2 * (each lower level page size) + (top level page size)) 1291 - * Should be reasonably bound.. 1292 - */ 1293 - xe_tile_assert(tile, batch_size < SZ_128K); 1294 - 1295 - bb = xe_bb_new(gt, batch_size, !q && xe->info.has_usm); 1333 + bb = xe_bb_new(gt, batch_size, usm); 1296 1334 if (IS_ERR(bb)) 1297 1335 return ERR_CAST(bb); 1298 1336 1299 1337 /* For sysmem PTE's, need to map them in our hole.. */ 1300 1338 if (!IS_DGFX(xe)) { 1301 - ppgtt_ofs = NUM_KERNEL_PDE - 1; 1302 - if (q) { 1303 - xe_tile_assert(tile, num_updates <= NUM_VMUSA_WRITES_PER_UNIT); 1339 + u32 ptes, ofs; 1304 1340 1305 - sa_bo = drm_suballoc_new(&m->vm_update_sa, 1, 1341 + ppgtt_ofs = NUM_KERNEL_PDE - 1; 1342 + if (!is_migrate) { 1343 + u32 num_units = DIV_ROUND_UP(num_updates, 1344 + NUM_VMUSA_WRITES_PER_UNIT); 1345 + 1346 + if (num_units > m->vm_update_sa.size) { 1347 + err = -ENOBUFS; 1348 + goto err_bb; 1349 + } 1350 + sa_bo = drm_suballoc_new(&m->vm_update_sa, num_units, 1306 1351 GFP_KERNEL, true, 0); 1307 1352 if (IS_ERR(sa_bo)) { 1308 1353 err = PTR_ERR(sa_bo); ··· 1312 1369 } 1313 1370 1314 1371 /* Map our PT's to gtt */ 1315 - bb->cs[bb->len++] = MI_STORE_DATA_IMM | MI_SDI_NUM_QW(num_updates); 1316 - bb->cs[bb->len++] = ppgtt_ofs * XE_PAGE_SIZE + page_ofs; 1317 - bb->cs[bb->len++] = 0; /* upper_32_bits */ 1372 + i = 0; 1373 + j = 0; 1374 + ptes = num_updates; 1375 + ofs = ppgtt_ofs * XE_PAGE_SIZE + page_ofs; 1376 + while (ptes) { 1377 + u32 chunk = min(MAX_PTE_PER_SDI, ptes); 1378 + u32 idx = 0; 1318 1379 1319 - for (i = 0; i < num_updates; i++) { 1320 - struct xe_bo *pt_bo = updates[i].pt_bo; 1380 + bb->cs[bb->len++] = MI_STORE_DATA_IMM | 1381 + MI_SDI_NUM_QW(chunk); 1382 + bb->cs[bb->len++] = ofs; 1383 + bb->cs[bb->len++] = 0; /* upper_32_bits */ 1321 1384 1322 - xe_tile_assert(tile, pt_bo->size == SZ_4K); 1385 + for (; i < pt_update_ops->num_ops; ++i) { 1386 + struct xe_vm_pgtable_update_op *pt_op = 1387 + &pt_update_ops->ops[i]; 1388 + struct xe_vm_pgtable_update *updates = pt_op->entries; 1323 1389 1324 - addr = vm->pt_ops->pte_encode_bo(pt_bo, 0, pat_index, 0); 1325 - bb->cs[bb->len++] = lower_32_bits(addr); 1326 - bb->cs[bb->len++] = upper_32_bits(addr); 1390 + for (; j < pt_op->num_entries; ++j, ++current_update, ++idx) { 1391 + struct xe_vm *vm = pt_update->vops->vm; 1392 + struct xe_bo *pt_bo = updates[j].pt_bo; 1393 + 1394 + if (idx == chunk) 1395 + goto next_cmd; 1396 + 1397 + xe_tile_assert(tile, pt_bo->size == SZ_4K); 1398 + 1399 + /* Map a PT at most once */ 1400 + if (pt_bo->update_index < 0) 1401 + pt_bo->update_index = current_update; 1402 + 1403 + addr = vm->pt_ops->pte_encode_bo(pt_bo, 0, 1404 + XE_CACHE_WB, 0); 1405 + bb->cs[bb->len++] = lower_32_bits(addr); 1406 + bb->cs[bb->len++] = upper_32_bits(addr); 1407 + } 1408 + 1409 + j = 0; 1410 + } 1411 + 1412 + next_cmd: 1413 + ptes -= chunk; 1414 + ofs += chunk * sizeof(u64); 1327 1415 } 1328 1416 1329 1417 bb->cs[bb->len++] = MI_BATCH_BUFFER_END; ··· 1362 1388 1363 1389 addr = xe_migrate_vm_addr(ppgtt_ofs, 0) + 1364 1390 (page_ofs / sizeof(u64)) * XE_PAGE_SIZE; 1365 - for (i = 0; i < num_updates; i++) 1366 - write_pgtable(tile, bb, addr + i * XE_PAGE_SIZE, 1367 - &updates[i], pt_update); 1391 + for (i = 0; i < pt_update_ops->num_ops; ++i) { 1392 + struct xe_vm_pgtable_update_op *pt_op = 1393 + &pt_update_ops->ops[i]; 1394 + struct xe_vm_pgtable_update *updates = pt_op->entries; 1395 + 1396 + for (j = 0; j < pt_op->num_entries; ++j) { 1397 + struct xe_bo *pt_bo = updates[j].pt_bo; 1398 + 1399 + write_pgtable(tile, bb, addr + 1400 + pt_bo->update_index * XE_PAGE_SIZE, 1401 + pt_op, &updates[j], pt_update); 1402 + } 1403 + } 1368 1404 } else { 1369 1405 /* phys pages, no preamble required */ 1370 1406 bb->cs[bb->len++] = MI_BATCH_BUFFER_END; 1371 1407 update_idx = bb->len; 1372 1408 1373 - for (i = 0; i < num_updates; i++) 1374 - write_pgtable(tile, bb, 0, &updates[i], pt_update); 1409 + for (i = 0; i < pt_update_ops->num_ops; ++i) { 1410 + struct xe_vm_pgtable_update_op *pt_op = 1411 + &pt_update_ops->ops[i]; 1412 + struct xe_vm_pgtable_update *updates = pt_op->entries; 1413 + 1414 + for (j = 0; j < pt_op->num_entries; ++j) 1415 + write_pgtable(tile, bb, 0, pt_op, &updates[j], 1416 + pt_update); 1417 + } 1375 1418 } 1376 1419 1377 - job = xe_bb_create_migration_job(q ?: m->q, bb, 1420 + job = xe_bb_create_migration_job(pt_update_ops->q, bb, 1378 1421 xe_migrate_batch_base(m, usm), 1379 1422 update_idx); 1380 1423 if (IS_ERR(job)) { ··· 1399 1408 goto err_sa; 1400 1409 } 1401 1410 1402 - /* Wait on BO move */ 1403 - if (bo) { 1404 - err = xe_sched_job_add_deps(job, bo->ttm.base.resv, 1405 - DMA_RESV_USAGE_KERNEL); 1406 - if (err) 1407 - goto err_job; 1408 - } 1409 - 1410 - /* 1411 - * Munmap style VM unbind, need to wait for all jobs to be complete / 1412 - * trigger preempts before moving forward 1413 - */ 1414 - if (first_munmap_rebind) { 1415 - err = xe_sched_job_add_deps(job, xe_vm_resv(vm), 1416 - DMA_RESV_USAGE_BOOKKEEP); 1417 - if (err) 1418 - goto err_job; 1419 - } 1420 - 1421 - err = xe_sched_job_last_fence_add_dep(job, vm); 1422 - for (i = 0; !err && i < num_syncs; i++) 1423 - err = xe_sync_entry_add_deps(&syncs[i], job); 1424 - 1425 - if (err) 1426 - goto err_job; 1427 - 1428 1411 if (ops->pre_commit) { 1429 1412 pt_update->job = job; 1430 1413 err = ops->pre_commit(pt_update); 1431 1414 if (err) 1432 1415 goto err_job; 1433 1416 } 1434 - if (!q) 1417 + if (is_migrate) 1435 1418 mutex_lock(&m->job_mutex); 1436 1419 1437 1420 xe_sched_job_arm(job); 1438 1421 fence = dma_fence_get(&job->drm.s_fence->finished); 1439 1422 xe_sched_job_push(job); 1440 1423 1441 - if (!q) 1424 + if (is_migrate) 1442 1425 mutex_unlock(&m->job_mutex); 1443 1426 1444 1427 xe_bb_free(bb, fence); ··· 1427 1462 err_bb: 1428 1463 xe_bb_free(bb, NULL); 1429 1464 return ERR_PTR(err); 1465 + } 1466 + 1467 + /** 1468 + * xe_migrate_update_pgtables() - Pipelined page-table update 1469 + * @m: The migrate context. 1470 + * @pt_update: PT update arguments 1471 + * 1472 + * Perform a pipelined page-table update. The update descriptors are typically 1473 + * built under the same lock critical section as a call to this function. If 1474 + * using the default engine for the updates, they will be performed in the 1475 + * order they grab the job_mutex. If different engines are used, external 1476 + * synchronization is needed for overlapping updates to maintain page-table 1477 + * consistency. Note that the meaing of "overlapping" is that the updates 1478 + * touch the same page-table, which might be a higher-level page-directory. 1479 + * If no pipelining is needed, then updates may be performed by the cpu. 1480 + * 1481 + * Return: A dma_fence that, when signaled, indicates the update completion. 1482 + */ 1483 + struct dma_fence * 1484 + xe_migrate_update_pgtables(struct xe_migrate *m, 1485 + struct xe_migrate_pt_update *pt_update) 1486 + 1487 + { 1488 + struct xe_vm_pgtable_update_ops *pt_update_ops = 1489 + &pt_update->vops->pt_update_ops[pt_update->tile_id]; 1490 + struct dma_fence *fence; 1491 + 1492 + fence = xe_migrate_update_pgtables_cpu(m, pt_update); 1493 + 1494 + /* -ETIME indicates a job is needed, anything else is legit error */ 1495 + if (!IS_ERR(fence) || PTR_ERR(fence) != -ETIME) 1496 + return fence; 1497 + 1498 + return __xe_migrate_update_pgtables(m, pt_update, pt_update_ops); 1430 1499 } 1431 1500 1432 1501 /**
+20 -12
drivers/gpu/drm/xe/xe_migrate.h
··· 47 47 struct xe_tile *tile, struct iosys_map *map, 48 48 void *pos, u32 ofs, u32 num_qwords, 49 49 const struct xe_vm_pgtable_update *update); 50 + /** 51 + * @clear: Clear a command buffer or page-table with ptes. 52 + * @pt_update: Embeddable callback argument. 53 + * @tile: The tile for the current operation. 54 + * @map: struct iosys_map into the memory to be populated. 55 + * @pos: If @map is NULL, map into the memory to be populated. 56 + * @ofs: qword offset into @map, unused if @map is NULL. 57 + * @num_qwords: Number of qwords to write. 58 + * @update: Information about the PTEs to be inserted. 59 + * 60 + * This interface is intended to be used as a callback into the 61 + * page-table system to populate command buffers or shared 62 + * page-tables with PTEs. 63 + */ 64 + void (*clear)(struct xe_migrate_pt_update *pt_update, 65 + struct xe_tile *tile, struct iosys_map *map, 66 + void *pos, u32 ofs, u32 num_qwords, 67 + const struct xe_vm_pgtable_update *update); 50 68 51 69 /** 52 70 * @pre_commit: Callback to be called just before arming the ··· 85 67 struct xe_migrate_pt_update { 86 68 /** @ops: Pointer to the struct xe_migrate_pt_update_ops callbacks */ 87 69 const struct xe_migrate_pt_update_ops *ops; 88 - /** @vma: The vma we're updating the pagetable for. */ 89 - struct xe_vma *vma; 70 + /** @vops: VMA operations */ 71 + struct xe_vma_ops *vops; 90 72 /** @job: The job if a GPU page-table update. NULL otherwise */ 91 73 struct xe_sched_job *job; 92 - /** @start: Start of update for the range fence */ 93 - u64 start; 94 - /** @last: Last of update for the range fence */ 95 - u64 last; 96 74 /** @tile_id: Tile ID of the update */ 97 75 u8 tile_id; 98 76 }; ··· 110 96 111 97 struct dma_fence * 112 98 xe_migrate_update_pgtables(struct xe_migrate *m, 113 - struct xe_vm *vm, 114 - struct xe_bo *bo, 115 - struct xe_exec_queue *q, 116 - const struct xe_vm_pgtable_update *updates, 117 - u32 num_updates, 118 - struct xe_sync_entry *syncs, u32 num_syncs, 119 99 struct xe_migrate_pt_update *pt_update); 120 100 121 101 void xe_migrate_wait(struct xe_migrate *m);
+711 -415
drivers/gpu/drm/xe/xe_pt.c
··· 9 9 #include "xe_bo.h" 10 10 #include "xe_device.h" 11 11 #include "xe_drm_client.h" 12 + #include "xe_exec_queue.h" 12 13 #include "xe_gt.h" 13 14 #include "xe_gt_tlb_invalidation.h" 14 15 #include "xe_migrate.h" 15 16 #include "xe_pt_types.h" 16 17 #include "xe_pt_walk.h" 17 18 #include "xe_res_cursor.h" 19 + #include "xe_sched_job.h" 20 + #include "xe_sync.h" 18 21 #include "xe_trace.h" 19 22 #include "xe_ttm_stolen_mgr.h" 20 23 #include "xe_vm.h" ··· 328 325 entry->pt = parent; 329 326 entry->flags = 0; 330 327 entry->qwords = 0; 328 + entry->pt_bo->update_index = -1; 331 329 332 330 if (alloc_entries) { 333 331 entry->pt_entries = kmalloc_array(XE_PDES, ··· 868 864 869 865 lockdep_assert_held(&vm->lock); 870 866 871 - if (xe_vma_is_userptr(vma)) 872 - lockdep_assert_held_read(&vm->userptr.notifier_lock); 873 - else if (!xe_vma_is_null(vma)) 867 + if (!xe_vma_is_userptr(vma) && !xe_vma_is_null(vma)) 874 868 dma_resv_assert_held(xe_vma_bo(vma)->ttm.base.resv); 875 869 876 870 xe_vm_assert_held(vm); ··· 890 888 if (!rebind) 891 889 pt->num_live += entries[i].qwords; 892 890 893 - if (!pt->level) { 894 - kfree(entries[i].pt_entries); 891 + if (!pt->level) 895 892 continue; 896 - } 897 893 898 894 pt_dir = as_xe_pt_dir(pt); 899 895 for (j = 0; j < entries[i].qwords; j++) { ··· 904 904 905 905 pt_dir->children[j_] = &newpte->base; 906 906 } 907 - kfree(entries[i].pt_entries); 908 907 } 908 + } 909 + 910 + static void xe_pt_free_bind(struct xe_vm_pgtable_update *entries, 911 + u32 num_entries) 912 + { 913 + u32 i; 914 + 915 + for (i = 0; i < num_entries; i++) 916 + kfree(entries[i].pt_entries); 909 917 } 910 918 911 919 static int ··· 934 926 935 927 static void xe_vm_dbg_print_entries(struct xe_device *xe, 936 928 const struct xe_vm_pgtable_update *entries, 937 - unsigned int num_entries) 929 + unsigned int num_entries, bool bind) 938 930 #if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)) 939 931 { 940 932 unsigned int i; 941 933 942 - vm_dbg(&xe->drm, "%u entries to update\n", num_entries); 934 + vm_dbg(&xe->drm, "%s: %u entries to update\n", bind ? "bind" : "unbind", 935 + num_entries); 943 936 for (i = 0; i < num_entries; i++) { 944 937 const struct xe_vm_pgtable_update *entry = &entries[i]; 945 938 struct xe_pt *xe_pt = entry->pt; ··· 961 952 {} 962 953 #endif 963 954 964 - #ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT 965 - 966 - static int xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) 955 + static bool no_in_syncs(struct xe_sync_entry *syncs, u32 num_syncs) 967 956 { 968 - u32 divisor = uvma->userptr.divisor ? uvma->userptr.divisor : 2; 969 - static u32 count; 957 + int i; 970 958 971 - if (count++ % divisor == divisor - 1) { 972 - struct xe_vm *vm = xe_vma_vm(&uvma->vma); 959 + for (i = 0; i < num_syncs; i++) { 960 + struct dma_fence *fence = syncs[i].fence; 973 961 974 - uvma->userptr.divisor = divisor << 1; 975 - spin_lock(&vm->userptr.invalidated_lock); 976 - list_move_tail(&uvma->userptr.invalidate_link, 977 - &vm->userptr.invalidated); 978 - spin_unlock(&vm->userptr.invalidated_lock); 979 - return true; 962 + if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, 963 + &fence->flags)) 964 + return false; 980 965 } 981 966 982 - return false; 967 + return true; 983 968 } 984 969 985 - #else 986 - 987 - static bool xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) 970 + static int job_test_add_deps(struct xe_sched_job *job, 971 + struct dma_resv *resv, 972 + enum dma_resv_usage usage) 988 973 { 989 - return false; 974 + if (!job) { 975 + if (!dma_resv_test_signaled(resv, usage)) 976 + return -ETIME; 977 + 978 + return 0; 979 + } 980 + 981 + return xe_sched_job_add_deps(job, resv, usage); 990 982 } 991 983 992 - #endif 984 + static int vma_add_deps(struct xe_vma *vma, struct xe_sched_job *job) 985 + { 986 + struct xe_bo *bo = xe_vma_bo(vma); 993 987 994 - /** 995 - * struct xe_pt_migrate_pt_update - Callback argument for pre-commit callbacks 996 - * @base: Base we derive from. 997 - * @bind: Whether this is a bind or an unbind operation. A bind operation 998 - * makes the pre-commit callback error with -EAGAIN if it detects a 999 - * pending invalidation. 1000 - * @locked: Whether the pre-commit callback locked the userptr notifier lock 1001 - * and it needs unlocking. 1002 - */ 1003 - struct xe_pt_migrate_pt_update { 1004 - struct xe_migrate_pt_update base; 1005 - bool bind; 1006 - bool locked; 1007 - }; 988 + xe_bo_assert_held(bo); 1008 989 1009 - /* 1010 - * This function adds the needed dependencies to a page-table update job 1011 - * to make sure racing jobs for separate bind engines don't race writing 1012 - * to the same page-table range, wreaking havoc. Initially use a single 1013 - * fence for the entire VM. An optimization would use smaller granularity. 1014 - */ 990 + if (bo && !bo->vm) 991 + return job_test_add_deps(job, bo->ttm.base.resv, 992 + DMA_RESV_USAGE_KERNEL); 993 + 994 + return 0; 995 + } 996 + 997 + static int op_add_deps(struct xe_vm *vm, struct xe_vma_op *op, 998 + struct xe_sched_job *job) 999 + { 1000 + int err = 0; 1001 + 1002 + switch (op->base.op) { 1003 + case DRM_GPUVA_OP_MAP: 1004 + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) 1005 + break; 1006 + 1007 + err = vma_add_deps(op->map.vma, job); 1008 + break; 1009 + case DRM_GPUVA_OP_REMAP: 1010 + if (op->remap.prev) 1011 + err = vma_add_deps(op->remap.prev, job); 1012 + if (!err && op->remap.next) 1013 + err = vma_add_deps(op->remap.next, job); 1014 + break; 1015 + case DRM_GPUVA_OP_UNMAP: 1016 + break; 1017 + case DRM_GPUVA_OP_PREFETCH: 1018 + err = vma_add_deps(gpuva_to_vma(op->base.prefetch.va), job); 1019 + break; 1020 + default: 1021 + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); 1022 + } 1023 + 1024 + return err; 1025 + } 1026 + 1015 1027 static int xe_pt_vm_dependencies(struct xe_sched_job *job, 1016 - struct xe_range_fence_tree *rftree, 1017 - u64 start, u64 last) 1028 + struct xe_vm *vm, 1029 + struct xe_vma_ops *vops, 1030 + struct xe_vm_pgtable_update_ops *pt_update_ops, 1031 + struct xe_range_fence_tree *rftree) 1018 1032 { 1019 1033 struct xe_range_fence *rtfence; 1020 1034 struct dma_fence *fence; 1021 - int err; 1035 + struct xe_vma_op *op; 1036 + int err = 0, i; 1022 1037 1023 - rtfence = xe_range_fence_tree_first(rftree, start, last); 1038 + xe_vm_assert_held(vm); 1039 + 1040 + if (!job && !no_in_syncs(vops->syncs, vops->num_syncs)) 1041 + return -ETIME; 1042 + 1043 + if (!job && !xe_exec_queue_is_idle(pt_update_ops->q)) 1044 + return -ETIME; 1045 + 1046 + if (pt_update_ops->wait_vm_bookkeep || pt_update_ops->wait_vm_kernel) { 1047 + err = job_test_add_deps(job, xe_vm_resv(vm), 1048 + pt_update_ops->wait_vm_bookkeep ? 1049 + DMA_RESV_USAGE_BOOKKEEP : 1050 + DMA_RESV_USAGE_KERNEL); 1051 + if (err) 1052 + return err; 1053 + } 1054 + 1055 + rtfence = xe_range_fence_tree_first(rftree, pt_update_ops->start, 1056 + pt_update_ops->last); 1024 1057 while (rtfence) { 1025 1058 fence = rtfence->fence; 1026 1059 ··· 1080 1029 return err; 1081 1030 } 1082 1031 1083 - rtfence = xe_range_fence_tree_next(rtfence, start, last); 1032 + rtfence = xe_range_fence_tree_next(rtfence, 1033 + pt_update_ops->start, 1034 + pt_update_ops->last); 1084 1035 } 1085 1036 1086 - return 0; 1037 + list_for_each_entry(op, &vops->list, link) { 1038 + err = op_add_deps(vm, op, job); 1039 + if (err) 1040 + return err; 1041 + } 1042 + 1043 + if (job) 1044 + err = xe_sched_job_last_fence_add_dep(job, vm); 1045 + else 1046 + err = xe_exec_queue_last_fence_test_dep(pt_update_ops->q, vm); 1047 + 1048 + for (i = 0; job && !err && i < vops->num_syncs; i++) 1049 + err = xe_sync_entry_add_deps(&vops->syncs[i], job); 1050 + 1051 + return err; 1087 1052 } 1088 1053 1089 1054 static int xe_pt_pre_commit(struct xe_migrate_pt_update *pt_update) 1090 1055 { 1091 - struct xe_range_fence_tree *rftree = 1092 - &xe_vma_vm(pt_update->vma)->rftree[pt_update->tile_id]; 1056 + struct xe_vma_ops *vops = pt_update->vops; 1057 + struct xe_vm *vm = vops->vm; 1058 + struct xe_range_fence_tree *rftree = &vm->rftree[pt_update->tile_id]; 1059 + struct xe_vm_pgtable_update_ops *pt_update_ops = 1060 + &vops->pt_update_ops[pt_update->tile_id]; 1093 1061 1094 - return xe_pt_vm_dependencies(pt_update->job, rftree, 1095 - pt_update->start, pt_update->last); 1062 + return xe_pt_vm_dependencies(pt_update->job, vm, pt_update->vops, 1063 + pt_update_ops, rftree); 1096 1064 } 1097 1065 1098 - static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update) 1066 + #ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT 1067 + 1068 + static bool xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) 1099 1069 { 1100 - struct xe_pt_migrate_pt_update *userptr_update = 1101 - container_of(pt_update, typeof(*userptr_update), base); 1102 - struct xe_userptr_vma *uvma = to_userptr_vma(pt_update->vma); 1103 - unsigned long notifier_seq = uvma->userptr.notifier_seq; 1104 - struct xe_vm *vm = xe_vma_vm(&uvma->vma); 1105 - int err = xe_pt_vm_dependencies(pt_update->job, 1106 - &vm->rftree[pt_update->tile_id], 1107 - pt_update->start, 1108 - pt_update->last); 1070 + u32 divisor = uvma->userptr.divisor ? uvma->userptr.divisor : 2; 1071 + static u32 count; 1109 1072 1110 - if (err) 1111 - return err; 1112 - 1113 - userptr_update->locked = false; 1114 - 1115 - /* 1116 - * Wait until nobody is running the invalidation notifier, and 1117 - * since we're exiting the loop holding the notifier lock, 1118 - * nobody can proceed invalidating either. 1119 - * 1120 - * Note that we don't update the vma->userptr.notifier_seq since 1121 - * we don't update the userptr pages. 1122 - */ 1123 - do { 1124 - down_read(&vm->userptr.notifier_lock); 1125 - if (!mmu_interval_read_retry(&uvma->userptr.notifier, 1126 - notifier_seq)) 1127 - break; 1128 - 1129 - up_read(&vm->userptr.notifier_lock); 1130 - 1131 - if (userptr_update->bind) 1132 - return -EAGAIN; 1133 - 1134 - notifier_seq = mmu_interval_read_begin(&uvma->userptr.notifier); 1135 - } while (true); 1136 - 1137 - /* Inject errors to test_whether they are handled correctly */ 1138 - if (userptr_update->bind && xe_pt_userptr_inject_eagain(uvma)) { 1139 - up_read(&vm->userptr.notifier_lock); 1140 - return -EAGAIN; 1073 + if (count++ % divisor == divisor - 1) { 1074 + uvma->userptr.divisor = divisor << 1; 1075 + return true; 1141 1076 } 1142 1077 1143 - userptr_update->locked = true; 1078 + return false; 1079 + } 1080 + 1081 + #else 1082 + 1083 + static bool xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) 1084 + { 1085 + return false; 1086 + } 1087 + 1088 + #endif 1089 + 1090 + static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma, 1091 + struct xe_vm_pgtable_update_ops *pt_update) 1092 + { 1093 + struct xe_userptr_vma *uvma; 1094 + unsigned long notifier_seq; 1095 + 1096 + lockdep_assert_held_read(&vm->userptr.notifier_lock); 1097 + 1098 + if (!xe_vma_is_userptr(vma)) 1099 + return 0; 1100 + 1101 + uvma = to_userptr_vma(vma); 1102 + notifier_seq = uvma->userptr.notifier_seq; 1103 + 1104 + if (uvma->userptr.initial_bind && !xe_vm_in_fault_mode(vm)) 1105 + return 0; 1106 + 1107 + if (!mmu_interval_read_retry(&uvma->userptr.notifier, 1108 + notifier_seq) && 1109 + !xe_pt_userptr_inject_eagain(uvma)) 1110 + return 0; 1111 + 1112 + if (xe_vm_in_fault_mode(vm)) { 1113 + return -EAGAIN; 1114 + } else { 1115 + spin_lock(&vm->userptr.invalidated_lock); 1116 + list_move_tail(&uvma->userptr.invalidate_link, 1117 + &vm->userptr.invalidated); 1118 + spin_unlock(&vm->userptr.invalidated_lock); 1119 + 1120 + if (xe_vm_in_preempt_fence_mode(vm)) { 1121 + struct dma_resv_iter cursor; 1122 + struct dma_fence *fence; 1123 + long err; 1124 + 1125 + dma_resv_iter_begin(&cursor, xe_vm_resv(vm), 1126 + DMA_RESV_USAGE_BOOKKEEP); 1127 + dma_resv_for_each_fence_unlocked(&cursor, fence) 1128 + dma_fence_enable_sw_signaling(fence); 1129 + dma_resv_iter_end(&cursor); 1130 + 1131 + err = dma_resv_wait_timeout(xe_vm_resv(vm), 1132 + DMA_RESV_USAGE_BOOKKEEP, 1133 + false, MAX_SCHEDULE_TIMEOUT); 1134 + XE_WARN_ON(err <= 0); 1135 + } 1136 + } 1144 1137 1145 1138 return 0; 1146 1139 } 1147 1140 1148 - static const struct xe_migrate_pt_update_ops bind_ops = { 1149 - .populate = xe_vm_populate_pgtable, 1150 - .pre_commit = xe_pt_pre_commit, 1151 - }; 1141 + static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op, 1142 + struct xe_vm_pgtable_update_ops *pt_update) 1143 + { 1144 + int err = 0; 1152 1145 1153 - static const struct xe_migrate_pt_update_ops userptr_bind_ops = { 1154 - .populate = xe_vm_populate_pgtable, 1155 - .pre_commit = xe_pt_userptr_pre_commit, 1156 - }; 1146 + lockdep_assert_held_read(&vm->userptr.notifier_lock); 1147 + 1148 + switch (op->base.op) { 1149 + case DRM_GPUVA_OP_MAP: 1150 + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) 1151 + break; 1152 + 1153 + err = vma_check_userptr(vm, op->map.vma, pt_update); 1154 + break; 1155 + case DRM_GPUVA_OP_REMAP: 1156 + if (op->remap.prev) 1157 + err = vma_check_userptr(vm, op->remap.prev, pt_update); 1158 + if (!err && op->remap.next) 1159 + err = vma_check_userptr(vm, op->remap.next, pt_update); 1160 + break; 1161 + case DRM_GPUVA_OP_UNMAP: 1162 + break; 1163 + case DRM_GPUVA_OP_PREFETCH: 1164 + err = vma_check_userptr(vm, gpuva_to_vma(op->base.prefetch.va), 1165 + pt_update); 1166 + break; 1167 + default: 1168 + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); 1169 + } 1170 + 1171 + return err; 1172 + } 1173 + 1174 + static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update) 1175 + { 1176 + struct xe_vm *vm = pt_update->vops->vm; 1177 + struct xe_vma_ops *vops = pt_update->vops; 1178 + struct xe_vm_pgtable_update_ops *pt_update_ops = 1179 + &vops->pt_update_ops[pt_update->tile_id]; 1180 + struct xe_vma_op *op; 1181 + int err; 1182 + 1183 + err = xe_pt_pre_commit(pt_update); 1184 + if (err) 1185 + return err; 1186 + 1187 + down_read(&vm->userptr.notifier_lock); 1188 + 1189 + list_for_each_entry(op, &vops->list, link) { 1190 + err = op_check_userptr(vm, op, pt_update_ops); 1191 + if (err) { 1192 + up_read(&vm->userptr.notifier_lock); 1193 + break; 1194 + } 1195 + } 1196 + 1197 + return err; 1198 + } 1157 1199 1158 1200 struct invalidation_fence { 1159 1201 struct xe_gt_tlb_invalidation_fence base; ··· 1342 1198 xe_gt_assert(gt, !ret || ret == -ENOENT); 1343 1199 1344 1200 return ret && ret != -ENOENT ? ret : 0; 1345 - } 1346 - 1347 - static void xe_pt_calc_rfence_interval(struct xe_vma *vma, 1348 - struct xe_pt_migrate_pt_update *update, 1349 - struct xe_vm_pgtable_update *entries, 1350 - u32 num_entries) 1351 - { 1352 - int i, level = 0; 1353 - 1354 - for (i = 0; i < num_entries; i++) { 1355 - const struct xe_vm_pgtable_update *entry = &entries[i]; 1356 - 1357 - if (entry->pt->level > level) 1358 - level = entry->pt->level; 1359 - } 1360 - 1361 - /* Greedy (non-optimal) calculation but simple */ 1362 - update->base.start = ALIGN_DOWN(xe_vma_start(vma), 1363 - 0x1ull << xe_pt_shift(level)); 1364 - update->base.last = ALIGN(xe_vma_end(vma), 1365 - 0x1ull << xe_pt_shift(level)) - 1; 1366 - } 1367 - 1368 - /** 1369 - * __xe_pt_bind_vma() - Build and connect a page-table tree for the vma 1370 - * address range. 1371 - * @tile: The tile to bind for. 1372 - * @vma: The vma to bind. 1373 - * @q: The exec_queue with which to do pipelined page-table updates. 1374 - * @syncs: Entries to sync on before binding the built tree to the live vm tree. 1375 - * @num_syncs: Number of @sync entries. 1376 - * @rebind: Whether we're rebinding this vma to the same address range without 1377 - * an unbind in-between. 1378 - * 1379 - * This function builds a page-table tree (see xe_pt_stage_bind() for more 1380 - * information on page-table building), and the xe_vm_pgtable_update entries 1381 - * abstracting the operations needed to attach it to the main vm tree. It 1382 - * then takes the relevant locks and updates the metadata side of the main 1383 - * vm tree and submits the operations for pipelined attachment of the 1384 - * gpu page-table to the vm main tree, (which can be done either by the 1385 - * cpu and the GPU). 1386 - * 1387 - * Return: A valid dma-fence representing the pipelined attachment operation 1388 - * on success, an error pointer on error. 1389 - */ 1390 - struct dma_fence * 1391 - __xe_pt_bind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, 1392 - struct xe_sync_entry *syncs, u32 num_syncs, 1393 - bool rebind) 1394 - { 1395 - struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; 1396 - struct xe_pt_migrate_pt_update bind_pt_update = { 1397 - .base = { 1398 - .ops = xe_vma_is_userptr(vma) ? &userptr_bind_ops : &bind_ops, 1399 - .vma = vma, 1400 - .tile_id = tile->id, 1401 - }, 1402 - .bind = true, 1403 - }; 1404 - struct xe_vm *vm = xe_vma_vm(vma); 1405 - u32 num_entries; 1406 - struct dma_fence *fence; 1407 - struct invalidation_fence *ifence = NULL; 1408 - struct xe_range_fence *rfence; 1409 - int err; 1410 - 1411 - bind_pt_update.locked = false; 1412 - xe_bo_assert_held(xe_vma_bo(vma)); 1413 - xe_vm_assert_held(vm); 1414 - 1415 - vm_dbg(&xe_vma_vm(vma)->xe->drm, 1416 - "Preparing bind, with range [%llx...%llx) engine %p.\n", 1417 - xe_vma_start(vma), xe_vma_end(vma), q); 1418 - 1419 - err = xe_pt_prepare_bind(tile, vma, entries, &num_entries); 1420 - if (err) 1421 - goto err; 1422 - 1423 - err = dma_resv_reserve_fences(xe_vm_resv(vm), 1); 1424 - if (!err && !xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) 1425 - err = dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, 1); 1426 - if (err) 1427 - goto err; 1428 - 1429 - xe_tile_assert(tile, num_entries <= ARRAY_SIZE(entries)); 1430 - 1431 - xe_vm_dbg_print_entries(tile_to_xe(tile), entries, num_entries); 1432 - xe_pt_calc_rfence_interval(vma, &bind_pt_update, entries, 1433 - num_entries); 1434 - 1435 - /* 1436 - * If rebind, we have to invalidate TLB on !LR vms to invalidate 1437 - * cached PTEs point to freed memory. on LR vms this is done 1438 - * automatically when the context is re-enabled by the rebind worker, 1439 - * or in fault mode it was invalidated on PTE zapping. 1440 - * 1441 - * If !rebind, and scratch enabled VMs, there is a chance the scratch 1442 - * PTE is already cached in the TLB so it needs to be invalidated. 1443 - * on !LR VMs this is done in the ring ops preceding a batch, but on 1444 - * non-faulting LR, in particular on user-space batch buffer chaining, 1445 - * it needs to be done here. 1446 - */ 1447 - if ((!rebind && xe_vm_has_scratch(vm) && xe_vm_in_preempt_fence_mode(vm))) { 1448 - ifence = kzalloc(sizeof(*ifence), GFP_KERNEL); 1449 - if (!ifence) 1450 - return ERR_PTR(-ENOMEM); 1451 - } else if (rebind && !xe_vm_in_lr_mode(vm)) { 1452 - /* We bump also if batch_invalidate_tlb is true */ 1453 - vm->tlb_flush_seqno++; 1454 - } 1455 - 1456 - rfence = kzalloc(sizeof(*rfence), GFP_KERNEL); 1457 - if (!rfence) { 1458 - kfree(ifence); 1459 - return ERR_PTR(-ENOMEM); 1460 - } 1461 - 1462 - fence = xe_migrate_update_pgtables(tile->migrate, 1463 - vm, xe_vma_bo(vma), q, 1464 - entries, num_entries, 1465 - syncs, num_syncs, 1466 - &bind_pt_update.base); 1467 - if (!IS_ERR(fence)) { 1468 - bool last_munmap_rebind = vma->gpuva.flags & XE_VMA_LAST_REBIND; 1469 - LLIST_HEAD(deferred); 1470 - int err; 1471 - 1472 - err = xe_range_fence_insert(&vm->rftree[tile->id], rfence, 1473 - &xe_range_fence_kfree_ops, 1474 - bind_pt_update.base.start, 1475 - bind_pt_update.base.last, fence); 1476 - if (err) 1477 - dma_fence_wait(fence, false); 1478 - 1479 - /* TLB invalidation must be done before signaling rebind */ 1480 - if (ifence) { 1481 - int err = invalidation_fence_init(tile->primary_gt, 1482 - ifence, fence, 1483 - xe_vma_start(vma), 1484 - xe_vma_end(vma), 1485 - xe_vma_vm(vma)->usm.asid); 1486 - if (err) { 1487 - dma_fence_put(fence); 1488 - kfree(ifence); 1489 - return ERR_PTR(err); 1490 - } 1491 - fence = &ifence->base.base; 1492 - } 1493 - 1494 - /* add shared fence now for pagetable delayed destroy */ 1495 - dma_resv_add_fence(xe_vm_resv(vm), fence, rebind || 1496 - last_munmap_rebind ? 1497 - DMA_RESV_USAGE_KERNEL : 1498 - DMA_RESV_USAGE_BOOKKEEP); 1499 - 1500 - if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) 1501 - dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, 1502 - DMA_RESV_USAGE_BOOKKEEP); 1503 - xe_pt_commit_bind(vma, entries, num_entries, rebind, 1504 - bind_pt_update.locked ? &deferred : NULL); 1505 - 1506 - /* This vma is live (again?) now */ 1507 - vma->tile_present |= BIT(tile->id); 1508 - 1509 - if (bind_pt_update.locked) { 1510 - to_userptr_vma(vma)->userptr.initial_bind = true; 1511 - up_read(&vm->userptr.notifier_lock); 1512 - xe_bo_put_commit(&deferred); 1513 - } 1514 - if (!rebind && last_munmap_rebind && 1515 - xe_vm_in_preempt_fence_mode(vm)) 1516 - xe_vm_queue_rebind_worker(vm); 1517 - } else { 1518 - kfree(rfence); 1519 - kfree(ifence); 1520 - if (bind_pt_update.locked) 1521 - up_read(&vm->userptr.notifier_lock); 1522 - xe_pt_abort_bind(vma, entries, num_entries); 1523 - } 1524 - 1525 - return fence; 1526 - 1527 - err: 1528 - return ERR_PTR(err); 1529 1201 } 1530 1202 1531 1203 struct xe_pt_stage_unbind_walk { ··· 1494 1534 void *ptr, u32 qword_ofs, u32 num_qwords, 1495 1535 const struct xe_vm_pgtable_update *update) 1496 1536 { 1497 - struct xe_vma *vma = pt_update->vma; 1498 - u64 empty = __xe_pt_empty_pte(tile, xe_vma_vm(vma), update->pt->level); 1537 + struct xe_vm *vm = pt_update->vops->vm; 1538 + u64 empty = __xe_pt_empty_pte(tile, vm, update->pt->level); 1499 1539 int i; 1500 1540 1501 1541 if (map && map->is_iomem) ··· 1539 1579 } 1540 1580 } 1541 1581 1542 - static const struct xe_migrate_pt_update_ops unbind_ops = { 1543 - .populate = xe_migrate_clear_pgtable_callback, 1544 - .pre_commit = xe_pt_pre_commit, 1545 - }; 1546 - 1547 - static const struct xe_migrate_pt_update_ops userptr_unbind_ops = { 1548 - .populate = xe_migrate_clear_pgtable_callback, 1549 - .pre_commit = xe_pt_userptr_pre_commit, 1550 - }; 1551 - 1552 - /** 1553 - * __xe_pt_unbind_vma() - Disconnect and free a page-table tree for the vma 1554 - * address range. 1555 - * @tile: The tile to unbind for. 1556 - * @vma: The vma to unbind. 1557 - * @q: The exec_queue with which to do pipelined page-table updates. 1558 - * @syncs: Entries to sync on before disconnecting the tree to be destroyed. 1559 - * @num_syncs: Number of @sync entries. 1560 - * 1561 - * This function builds a the xe_vm_pgtable_update entries abstracting the 1562 - * operations needed to detach the page-table tree to be destroyed from the 1563 - * man vm tree. 1564 - * It then takes the relevant locks and submits the operations for 1565 - * pipelined detachment of the gpu page-table from the vm main tree, 1566 - * (which can be done either by the cpu and the GPU), Finally it frees the 1567 - * detached page-table tree. 1568 - * 1569 - * Return: A valid dma-fence representing the pipelined detachment operation 1570 - * on success, an error pointer on error. 1571 - */ 1572 - struct dma_fence * 1573 - __xe_pt_unbind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, 1574 - struct xe_sync_entry *syncs, u32 num_syncs) 1582 + static void 1583 + xe_pt_update_ops_rfence_interval(struct xe_vm_pgtable_update_ops *pt_update_ops, 1584 + struct xe_vma *vma) 1575 1585 { 1576 - struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; 1577 - struct xe_pt_migrate_pt_update unbind_pt_update = { 1578 - .base = { 1579 - .ops = xe_vma_is_userptr(vma) ? &userptr_unbind_ops : 1580 - &unbind_ops, 1581 - .vma = vma, 1582 - .tile_id = tile->id, 1583 - }, 1584 - }; 1585 - struct xe_vm *vm = xe_vma_vm(vma); 1586 - u32 num_entries; 1587 - struct dma_fence *fence = NULL; 1588 - struct invalidation_fence *ifence; 1589 - struct xe_range_fence *rfence; 1586 + u32 current_op = pt_update_ops->current_op; 1587 + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; 1588 + int i, level = 0; 1589 + u64 start, last; 1590 + 1591 + for (i = 0; i < pt_op->num_entries; i++) { 1592 + const struct xe_vm_pgtable_update *entry = &pt_op->entries[i]; 1593 + 1594 + if (entry->pt->level > level) 1595 + level = entry->pt->level; 1596 + } 1597 + 1598 + /* Greedy (non-optimal) calculation but simple */ 1599 + start = ALIGN_DOWN(xe_vma_start(vma), 0x1ull << xe_pt_shift(level)); 1600 + last = ALIGN(xe_vma_end(vma), 0x1ull << xe_pt_shift(level)) - 1; 1601 + 1602 + if (start < pt_update_ops->start) 1603 + pt_update_ops->start = start; 1604 + if (last > pt_update_ops->last) 1605 + pt_update_ops->last = last; 1606 + } 1607 + 1608 + static int vma_reserve_fences(struct xe_device *xe, struct xe_vma *vma) 1609 + { 1610 + if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) 1611 + return dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, 1612 + xe->info.tile_count); 1613 + 1614 + return 0; 1615 + } 1616 + 1617 + static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile, 1618 + struct xe_vm_pgtable_update_ops *pt_update_ops, 1619 + struct xe_vma *vma) 1620 + { 1621 + u32 current_op = pt_update_ops->current_op; 1622 + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; 1623 + struct llist_head *deferred = &pt_update_ops->deferred; 1590 1624 int err; 1591 1625 1592 - LLIST_HEAD(deferred); 1593 - 1594 1626 xe_bo_assert_held(xe_vma_bo(vma)); 1595 - xe_vm_assert_held(vm); 1596 1627 1597 1628 vm_dbg(&xe_vma_vm(vma)->xe->drm, 1598 - "Preparing unbind, with range [%llx...%llx) engine %p.\n", 1599 - xe_vma_start(vma), xe_vma_end(vma), q); 1629 + "Preparing bind, with range [%llx...%llx)\n", 1630 + xe_vma_start(vma), xe_vma_end(vma) - 1); 1600 1631 1601 - num_entries = xe_pt_stage_unbind(tile, vma, entries); 1602 - xe_tile_assert(tile, num_entries <= ARRAY_SIZE(entries)); 1632 + pt_op->vma = NULL; 1633 + pt_op->bind = true; 1634 + pt_op->rebind = BIT(tile->id) & vma->tile_present; 1603 1635 1604 - xe_vm_dbg_print_entries(tile_to_xe(tile), entries, num_entries); 1605 - xe_pt_calc_rfence_interval(vma, &unbind_pt_update, entries, 1606 - num_entries); 1607 - 1608 - err = dma_resv_reserve_fences(xe_vm_resv(vm), 1); 1609 - if (!err && !xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) 1610 - err = dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, 1); 1636 + err = vma_reserve_fences(tile_to_xe(tile), vma); 1611 1637 if (err) 1612 - return ERR_PTR(err); 1638 + return err; 1613 1639 1614 - ifence = kzalloc(sizeof(*ifence), GFP_KERNEL); 1615 - if (!ifence) 1616 - return ERR_PTR(-ENOMEM); 1640 + err = xe_pt_prepare_bind(tile, vma, pt_op->entries, 1641 + &pt_op->num_entries); 1642 + if (!err) { 1643 + xe_tile_assert(tile, pt_op->num_entries <= 1644 + ARRAY_SIZE(pt_op->entries)); 1645 + xe_vm_dbg_print_entries(tile_to_xe(tile), pt_op->entries, 1646 + pt_op->num_entries, true); 1617 1647 1618 - rfence = kzalloc(sizeof(*rfence), GFP_KERNEL); 1619 - if (!rfence) { 1620 - kfree(ifence); 1621 - return ERR_PTR(-ENOMEM); 1648 + xe_pt_update_ops_rfence_interval(pt_update_ops, vma); 1649 + ++pt_update_ops->current_op; 1650 + pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma); 1651 + 1652 + /* 1653 + * If rebind, we have to invalidate TLB on !LR vms to invalidate 1654 + * cached PTEs point to freed memory. On LR vms this is done 1655 + * automatically when the context is re-enabled by the rebind worker, 1656 + * or in fault mode it was invalidated on PTE zapping. 1657 + * 1658 + * If !rebind, and scratch enabled VMs, there is a chance the scratch 1659 + * PTE is already cached in the TLB so it needs to be invalidated. 1660 + * On !LR VMs this is done in the ring ops preceding a batch, but on 1661 + * non-faulting LR, in particular on user-space batch buffer chaining, 1662 + * it needs to be done here. 1663 + */ 1664 + if ((!pt_op->rebind && xe_vm_has_scratch(vm) && 1665 + xe_vm_in_preempt_fence_mode(vm))) 1666 + pt_update_ops->needs_invalidation = true; 1667 + else if (pt_op->rebind && !xe_vm_in_lr_mode(vm)) 1668 + /* We bump also if batch_invalidate_tlb is true */ 1669 + vm->tlb_flush_seqno++; 1670 + 1671 + /* FIXME: Don't commit right away */ 1672 + vma->tile_staged |= BIT(tile->id); 1673 + pt_op->vma = vma; 1674 + xe_pt_commit_bind(vma, pt_op->entries, pt_op->num_entries, 1675 + pt_op->rebind, deferred); 1676 + } 1677 + 1678 + return err; 1679 + } 1680 + 1681 + static int unbind_op_prepare(struct xe_tile *tile, 1682 + struct xe_vm_pgtable_update_ops *pt_update_ops, 1683 + struct xe_vma *vma) 1684 + { 1685 + u32 current_op = pt_update_ops->current_op; 1686 + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; 1687 + struct llist_head *deferred = &pt_update_ops->deferred; 1688 + int err; 1689 + 1690 + if (!((vma->tile_present | vma->tile_staged) & BIT(tile->id))) 1691 + return 0; 1692 + 1693 + xe_bo_assert_held(xe_vma_bo(vma)); 1694 + 1695 + vm_dbg(&xe_vma_vm(vma)->xe->drm, 1696 + "Preparing unbind, with range [%llx...%llx)\n", 1697 + xe_vma_start(vma), xe_vma_end(vma) - 1); 1698 + 1699 + /* 1700 + * Wait for invalidation to complete. Can corrupt internal page table 1701 + * state if an invalidation is running while preparing an unbind. 1702 + */ 1703 + if (xe_vma_is_userptr(vma) && xe_vm_in_fault_mode(xe_vma_vm(vma))) 1704 + mmu_interval_read_begin(&to_userptr_vma(vma)->userptr.notifier); 1705 + 1706 + pt_op->vma = vma; 1707 + pt_op->bind = false; 1708 + pt_op->rebind = false; 1709 + 1710 + err = vma_reserve_fences(tile_to_xe(tile), vma); 1711 + if (err) 1712 + return err; 1713 + 1714 + pt_op->num_entries = xe_pt_stage_unbind(tile, vma, pt_op->entries); 1715 + 1716 + xe_vm_dbg_print_entries(tile_to_xe(tile), pt_op->entries, 1717 + pt_op->num_entries, false); 1718 + xe_pt_update_ops_rfence_interval(pt_update_ops, vma); 1719 + ++pt_update_ops->current_op; 1720 + pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma); 1721 + pt_update_ops->needs_invalidation = true; 1722 + 1723 + /* FIXME: Don't commit right away */ 1724 + xe_pt_commit_unbind(vma, pt_op->entries, pt_op->num_entries, 1725 + deferred); 1726 + 1727 + return 0; 1728 + } 1729 + 1730 + static int op_prepare(struct xe_vm *vm, 1731 + struct xe_tile *tile, 1732 + struct xe_vm_pgtable_update_ops *pt_update_ops, 1733 + struct xe_vma_op *op) 1734 + { 1735 + int err = 0; 1736 + 1737 + xe_vm_assert_held(vm); 1738 + 1739 + switch (op->base.op) { 1740 + case DRM_GPUVA_OP_MAP: 1741 + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) 1742 + break; 1743 + 1744 + err = bind_op_prepare(vm, tile, pt_update_ops, op->map.vma); 1745 + pt_update_ops->wait_vm_kernel = true; 1746 + break; 1747 + case DRM_GPUVA_OP_REMAP: 1748 + err = unbind_op_prepare(tile, pt_update_ops, 1749 + gpuva_to_vma(op->base.remap.unmap->va)); 1750 + 1751 + if (!err && op->remap.prev) { 1752 + err = bind_op_prepare(vm, tile, pt_update_ops, 1753 + op->remap.prev); 1754 + pt_update_ops->wait_vm_bookkeep = true; 1755 + } 1756 + if (!err && op->remap.next) { 1757 + err = bind_op_prepare(vm, tile, pt_update_ops, 1758 + op->remap.next); 1759 + pt_update_ops->wait_vm_bookkeep = true; 1760 + } 1761 + break; 1762 + case DRM_GPUVA_OP_UNMAP: 1763 + err = unbind_op_prepare(tile, pt_update_ops, 1764 + gpuva_to_vma(op->base.unmap.va)); 1765 + break; 1766 + case DRM_GPUVA_OP_PREFETCH: 1767 + err = bind_op_prepare(vm, tile, pt_update_ops, 1768 + gpuva_to_vma(op->base.prefetch.va)); 1769 + pt_update_ops->wait_vm_kernel = true; 1770 + break; 1771 + default: 1772 + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); 1773 + } 1774 + 1775 + return err; 1776 + } 1777 + 1778 + static void 1779 + xe_pt_update_ops_init(struct xe_vm_pgtable_update_ops *pt_update_ops) 1780 + { 1781 + init_llist_head(&pt_update_ops->deferred); 1782 + pt_update_ops->start = ~0x0ull; 1783 + pt_update_ops->last = 0x0ull; 1784 + } 1785 + 1786 + /** 1787 + * xe_pt_update_ops_prepare() - Prepare PT update operations 1788 + * @tile: Tile of PT update operations 1789 + * @vops: VMA operationa 1790 + * 1791 + * Prepare PT update operations which includes updating internal PT state, 1792 + * allocate memory for page tables, populate page table being pruned in, and 1793 + * create PT update operations for leaf insertion / removal. 1794 + * 1795 + * Return: 0 on success, negative error code on error. 1796 + */ 1797 + int xe_pt_update_ops_prepare(struct xe_tile *tile, struct xe_vma_ops *vops) 1798 + { 1799 + struct xe_vm_pgtable_update_ops *pt_update_ops = 1800 + &vops->pt_update_ops[tile->id]; 1801 + struct xe_vma_op *op; 1802 + int err; 1803 + 1804 + lockdep_assert_held(&vops->vm->lock); 1805 + xe_vm_assert_held(vops->vm); 1806 + 1807 + xe_pt_update_ops_init(pt_update_ops); 1808 + 1809 + err = dma_resv_reserve_fences(xe_vm_resv(vops->vm), 1810 + tile_to_xe(tile)->info.tile_count); 1811 + if (err) 1812 + return err; 1813 + 1814 + list_for_each_entry(op, &vops->list, link) { 1815 + err = op_prepare(vops->vm, tile, pt_update_ops, op); 1816 + 1817 + if (err) 1818 + return err; 1819 + } 1820 + 1821 + xe_tile_assert(tile, pt_update_ops->current_op <= 1822 + pt_update_ops->num_ops); 1823 + 1824 + return 0; 1825 + } 1826 + 1827 + static void bind_op_commit(struct xe_vm *vm, struct xe_tile *tile, 1828 + struct xe_vm_pgtable_update_ops *pt_update_ops, 1829 + struct xe_vma *vma, struct dma_fence *fence) 1830 + { 1831 + if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) 1832 + dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, 1833 + pt_update_ops->wait_vm_bookkeep ? 1834 + DMA_RESV_USAGE_KERNEL : 1835 + DMA_RESV_USAGE_BOOKKEEP); 1836 + vma->tile_present |= BIT(tile->id); 1837 + vma->tile_staged &= ~BIT(tile->id); 1838 + if (xe_vma_is_userptr(vma)) { 1839 + lockdep_assert_held_read(&vm->userptr.notifier_lock); 1840 + to_userptr_vma(vma)->userptr.initial_bind = true; 1622 1841 } 1623 1842 1624 1843 /* 1625 - * Even if we were already evicted and unbind to destroy, we need to 1626 - * clear again here. The eviction may have updated pagetables at a 1627 - * lower level, because it needs to be more conservative. 1844 + * Kick rebind worker if this bind triggers preempt fences and not in 1845 + * the rebind worker 1628 1846 */ 1629 - fence = xe_migrate_update_pgtables(tile->migrate, 1630 - vm, NULL, q ? q : 1631 - vm->q[tile->id], 1632 - entries, num_entries, 1633 - syncs, num_syncs, 1634 - &unbind_pt_update.base); 1635 - if (!IS_ERR(fence)) { 1636 - int err; 1847 + if (pt_update_ops->wait_vm_bookkeep && 1848 + xe_vm_in_preempt_fence_mode(vm) && 1849 + !current->mm) 1850 + xe_vm_queue_rebind_worker(vm); 1851 + } 1637 1852 1638 - err = xe_range_fence_insert(&vm->rftree[tile->id], rfence, 1639 - &xe_range_fence_kfree_ops, 1640 - unbind_pt_update.base.start, 1641 - unbind_pt_update.base.last, fence); 1642 - if (err) 1643 - dma_fence_wait(fence, false); 1644 - 1645 - /* TLB invalidation must be done before signaling unbind */ 1646 - err = invalidation_fence_init(tile->primary_gt, ifence, fence, 1647 - xe_vma_start(vma), 1648 - xe_vma_end(vma), 1649 - xe_vma_vm(vma)->usm.asid); 1650 - if (err) { 1651 - dma_fence_put(fence); 1652 - kfree(ifence); 1653 - return ERR_PTR(err); 1654 - } 1655 - fence = &ifence->base.base; 1656 - 1657 - /* add shared fence now for pagetable delayed destroy */ 1658 - dma_resv_add_fence(xe_vm_resv(vm), fence, 1853 + static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile, 1854 + struct xe_vm_pgtable_update_ops *pt_update_ops, 1855 + struct xe_vma *vma, struct dma_fence *fence) 1856 + { 1857 + if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) 1858 + dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, 1859 + pt_update_ops->wait_vm_bookkeep ? 1860 + DMA_RESV_USAGE_KERNEL : 1659 1861 DMA_RESV_USAGE_BOOKKEEP); 1660 - 1661 - /* This fence will be installed by caller when doing eviction */ 1662 - if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) 1663 - dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, 1664 - DMA_RESV_USAGE_BOOKKEEP); 1665 - xe_pt_commit_unbind(vma, entries, num_entries, 1666 - unbind_pt_update.locked ? &deferred : NULL); 1667 - vma->tile_present &= ~BIT(tile->id); 1668 - } else { 1669 - kfree(rfence); 1670 - kfree(ifence); 1671 - } 1672 - 1673 - if (!vma->tile_present) 1862 + vma->tile_present &= ~BIT(tile->id); 1863 + if (!vma->tile_present) { 1674 1864 list_del_init(&vma->combined_links.rebind); 1865 + if (xe_vma_is_userptr(vma)) { 1866 + lockdep_assert_held_read(&vm->userptr.notifier_lock); 1675 1867 1676 - if (unbind_pt_update.locked) { 1677 - xe_tile_assert(tile, xe_vma_is_userptr(vma)); 1678 - 1679 - if (!vma->tile_present) { 1680 1868 spin_lock(&vm->userptr.invalidated_lock); 1681 1869 list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link); 1682 1870 spin_unlock(&vm->userptr.invalidated_lock); 1683 1871 } 1684 - up_read(&vm->userptr.notifier_lock); 1685 - xe_bo_put_commit(&deferred); 1872 + } 1873 + } 1874 + 1875 + static void op_commit(struct xe_vm *vm, 1876 + struct xe_tile *tile, 1877 + struct xe_vm_pgtable_update_ops *pt_update_ops, 1878 + struct xe_vma_op *op, struct dma_fence *fence) 1879 + { 1880 + xe_vm_assert_held(vm); 1881 + 1882 + switch (op->base.op) { 1883 + case DRM_GPUVA_OP_MAP: 1884 + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) 1885 + break; 1886 + 1887 + bind_op_commit(vm, tile, pt_update_ops, op->map.vma, fence); 1888 + break; 1889 + case DRM_GPUVA_OP_REMAP: 1890 + unbind_op_commit(vm, tile, pt_update_ops, 1891 + gpuva_to_vma(op->base.remap.unmap->va), fence); 1892 + 1893 + if (op->remap.prev) 1894 + bind_op_commit(vm, tile, pt_update_ops, op->remap.prev, 1895 + fence); 1896 + if (op->remap.next) 1897 + bind_op_commit(vm, tile, pt_update_ops, op->remap.next, 1898 + fence); 1899 + break; 1900 + case DRM_GPUVA_OP_UNMAP: 1901 + unbind_op_commit(vm, tile, pt_update_ops, 1902 + gpuva_to_vma(op->base.unmap.va), fence); 1903 + break; 1904 + case DRM_GPUVA_OP_PREFETCH: 1905 + bind_op_commit(vm, tile, pt_update_ops, 1906 + gpuva_to_vma(op->base.prefetch.va), fence); 1907 + break; 1908 + default: 1909 + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); 1910 + } 1911 + } 1912 + 1913 + static const struct xe_migrate_pt_update_ops migrate_ops = { 1914 + .populate = xe_vm_populate_pgtable, 1915 + .clear = xe_migrate_clear_pgtable_callback, 1916 + .pre_commit = xe_pt_pre_commit, 1917 + }; 1918 + 1919 + static const struct xe_migrate_pt_update_ops userptr_migrate_ops = { 1920 + .populate = xe_vm_populate_pgtable, 1921 + .clear = xe_migrate_clear_pgtable_callback, 1922 + .pre_commit = xe_pt_userptr_pre_commit, 1923 + }; 1924 + 1925 + /** 1926 + * xe_pt_update_ops_run() - Run PT update operations 1927 + * @tile: Tile of PT update operations 1928 + * @vops: VMA operationa 1929 + * 1930 + * Run PT update operations which includes committing internal PT state changes, 1931 + * creating job for PT update operations for leaf insertion / removal, and 1932 + * installing job fence in various places. 1933 + * 1934 + * Return: fence on success, negative ERR_PTR on error. 1935 + */ 1936 + struct dma_fence * 1937 + xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops) 1938 + { 1939 + struct xe_vm *vm = vops->vm; 1940 + struct xe_vm_pgtable_update_ops *pt_update_ops = 1941 + &vops->pt_update_ops[tile->id]; 1942 + struct dma_fence *fence; 1943 + struct invalidation_fence *ifence = NULL; 1944 + struct xe_range_fence *rfence; 1945 + struct xe_vma_op *op; 1946 + int err = 0; 1947 + struct xe_migrate_pt_update update = { 1948 + .ops = pt_update_ops->needs_userptr_lock ? 1949 + &userptr_migrate_ops : 1950 + &migrate_ops, 1951 + .vops = vops, 1952 + .tile_id = tile->id, 1953 + }; 1954 + 1955 + lockdep_assert_held(&vm->lock); 1956 + xe_vm_assert_held(vm); 1957 + 1958 + if (!pt_update_ops->current_op) { 1959 + xe_tile_assert(tile, xe_vm_in_fault_mode(vm)); 1960 + 1961 + return dma_fence_get_stub(); 1686 1962 } 1687 1963 1964 + if (pt_update_ops->needs_invalidation) { 1965 + ifence = kzalloc(sizeof(*ifence), GFP_KERNEL); 1966 + if (!ifence) 1967 + return ERR_PTR(-ENOMEM); 1968 + } 1969 + 1970 + rfence = kzalloc(sizeof(*rfence), GFP_KERNEL); 1971 + if (!rfence) { 1972 + err = -ENOMEM; 1973 + goto free_ifence; 1974 + } 1975 + 1976 + fence = xe_migrate_update_pgtables(tile->migrate, &update); 1977 + if (IS_ERR(fence)) { 1978 + err = PTR_ERR(fence); 1979 + goto free_rfence; 1980 + } 1981 + 1982 + if (xe_range_fence_insert(&vm->rftree[tile->id], rfence, 1983 + &xe_range_fence_kfree_ops, 1984 + pt_update_ops->start, 1985 + pt_update_ops->last, fence)) 1986 + dma_fence_wait(fence, false); 1987 + 1988 + /* tlb invalidation must be done before signaling rebind */ 1989 + if (ifence) { 1990 + err = invalidation_fence_init(tile->primary_gt, ifence, fence, 1991 + pt_update_ops->start, 1992 + pt_update_ops->last, 1993 + vm->usm.asid); 1994 + if (err) 1995 + goto put_fence; 1996 + fence = &ifence->base.base; 1997 + } 1998 + 1999 + dma_resv_add_fence(xe_vm_resv(vm), fence, 2000 + pt_update_ops->wait_vm_bookkeep ? 2001 + DMA_RESV_USAGE_KERNEL : 2002 + DMA_RESV_USAGE_BOOKKEEP); 2003 + 2004 + list_for_each_entry(op, &vops->list, link) 2005 + op_commit(vops->vm, tile, pt_update_ops, op, fence); 2006 + 2007 + if (pt_update_ops->needs_userptr_lock) 2008 + up_read(&vm->userptr.notifier_lock); 2009 + 1688 2010 return fence; 2011 + 2012 + put_fence: 2013 + if (pt_update_ops->needs_userptr_lock) 2014 + up_read(&vm->userptr.notifier_lock); 2015 + dma_fence_put(fence); 2016 + free_rfence: 2017 + kfree(rfence); 2018 + free_ifence: 2019 + kfree(ifence); 2020 + 2021 + return ERR_PTR(err); 2022 + } 2023 + 2024 + /** 2025 + * xe_pt_update_ops_fini() - Finish PT update operations 2026 + * @tile: Tile of PT update operations 2027 + * @vops: VMA operations 2028 + * 2029 + * Finish PT update operations by committing to destroy page table memory 2030 + */ 2031 + void xe_pt_update_ops_fini(struct xe_tile *tile, struct xe_vma_ops *vops) 2032 + { 2033 + struct xe_vm_pgtable_update_ops *pt_update_ops = 2034 + &vops->pt_update_ops[tile->id]; 2035 + int i; 2036 + 2037 + lockdep_assert_held(&vops->vm->lock); 2038 + xe_vm_assert_held(vops->vm); 2039 + 2040 + /* FIXME: Not 100% correct */ 2041 + for (i = 0; i < pt_update_ops->num_ops; ++i) { 2042 + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[i]; 2043 + 2044 + if (pt_op->bind) 2045 + xe_pt_free_bind(pt_op->entries, pt_op->num_entries); 2046 + } 2047 + xe_bo_put_commit(&vops->pt_update_ops[tile->id].deferred); 2048 + } 2049 + 2050 + /** 2051 + * xe_pt_update_ops_abort() - Abort PT update operations 2052 + * @tile: Tile of PT update operations 2053 + * @vops: VMA operationa 2054 + * 2055 + * Abort PT update operations by unwinding internal PT state 2056 + */ 2057 + void xe_pt_update_ops_abort(struct xe_tile *tile, struct xe_vma_ops *vops) 2058 + { 2059 + lockdep_assert_held(&vops->vm->lock); 2060 + xe_vm_assert_held(vops->vm); 2061 + 2062 + /* FIXME: Just kill VM for now + cleanup PTs */ 2063 + xe_bo_put_commit(&vops->pt_update_ops[tile->id].deferred); 2064 + xe_vm_kill(vops->vm, false); 1689 2065 }
+6 -8
drivers/gpu/drm/xe/xe_pt.h
··· 17 17 struct xe_tile; 18 18 struct xe_vm; 19 19 struct xe_vma; 20 + struct xe_vma_ops; 20 21 21 22 /* Largest huge pte is currently 1GiB. May become device dependent. */ 22 23 #define MAX_HUGEPTE_LEVEL 2 ··· 35 34 36 35 void xe_pt_destroy(struct xe_pt *pt, u32 flags, struct llist_head *deferred); 37 36 38 - struct dma_fence * 39 - __xe_pt_bind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, 40 - struct xe_sync_entry *syncs, u32 num_syncs, 41 - bool rebind); 42 - 43 - struct dma_fence * 44 - __xe_pt_unbind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, 45 - struct xe_sync_entry *syncs, u32 num_syncs); 37 + int xe_pt_update_ops_prepare(struct xe_tile *tile, struct xe_vma_ops *vops); 38 + struct dma_fence *xe_pt_update_ops_run(struct xe_tile *tile, 39 + struct xe_vma_ops *vops); 40 + void xe_pt_update_ops_fini(struct xe_tile *tile, struct xe_vma_ops *vops); 41 + void xe_pt_update_ops_abort(struct xe_tile *tile, struct xe_vma_ops *vops); 46 42 47 43 bool xe_pt_zap_ptes(struct xe_tile *tile, struct xe_vma *vma); 48 44
+36
drivers/gpu/drm/xe/xe_pt_types.h
··· 78 78 struct xe_vm_pgtable_update_op { 79 79 /** @entries: entries to update for this operation */ 80 80 struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; 81 + /** @vma: VMA for operation, operation not valid if NULL */ 82 + struct xe_vma *vma; 81 83 /** @num_entries: number of entries for this update operation */ 82 84 u32 num_entries; 83 85 /** @bind: is a bind */ 84 86 bool bind; 85 87 /** @rebind: is a rebind */ 86 88 bool rebind; 89 + }; 90 + 91 + /** struct xe_vm_pgtable_update_ops: page table update operations */ 92 + struct xe_vm_pgtable_update_ops { 93 + /** @ops: operations */ 94 + struct xe_vm_pgtable_update_op *ops; 95 + /** @deferred: deferred list to destroy PT entries */ 96 + struct llist_head deferred; 97 + /** @q: exec queue for PT operations */ 98 + struct xe_exec_queue *q; 99 + /** @start: start address of ops */ 100 + u64 start; 101 + /** @last: last address of ops */ 102 + u64 last; 103 + /** @num_ops: number of operations */ 104 + u32 num_ops; 105 + /** @current_op: current operations */ 106 + u32 current_op; 107 + /** @needs_userptr_lock: Needs userptr lock */ 108 + bool needs_userptr_lock; 109 + /** @needs_invalidation: Needs invalidation */ 110 + bool needs_invalidation; 111 + /** 112 + * @wait_vm_bookkeep: PT operations need to wait until VM is idle 113 + * (bookkeep dma-resv slots are idle) and stage all future VM activity 114 + * behind these operations (install PT operations into VM kernel 115 + * dma-resv slot). 116 + */ 117 + bool wait_vm_bookkeep; 118 + /** 119 + * @wait_vm_kernel: PT operations need to wait until VM kernel dma-resv 120 + * slots are idle. 121 + */ 122 + bool wait_vm_kernel; 87 123 }; 88 124 89 125 #endif
+7
drivers/gpu/drm/xe/xe_sa.c
··· 84 84 struct drm_suballoc *xe_sa_bo_new(struct xe_sa_manager *sa_manager, 85 85 unsigned int size) 86 86 { 87 + /* 88 + * BB to large, return -ENOBUFS indicating user should split 89 + * array of binds into smaller chunks. 90 + */ 91 + if (size > sa_manager->base.size) 92 + return ERR_PTR(-ENOBUFS); 93 + 87 94 return drm_suballoc_new(&sa_manager->base, size, GFP_KERNEL, true, 0); 88 95 } 89 96
+114 -407
drivers/gpu/drm/xe/xe_vm.c
··· 313 313 314 314 #define XE_VM_REBIND_RETRY_TIMEOUT_MS 1000 315 315 316 - /* 316 + /** 317 317 * xe_vm_kill() - VM Kill 318 318 * @vm: The VM. 319 319 * @unlocked: Flag indicates the VM's dma-resv is not held ··· 321 321 * Kill the VM by setting banned flag indicated VM is no longer available for 322 322 * use. If in preempt fence mode, also kill all exec queue attached to the VM. 323 323 */ 324 - static void xe_vm_kill(struct xe_vm *vm, bool unlocked) 324 + void xe_vm_kill(struct xe_vm *vm, bool unlocked) 325 325 { 326 326 struct xe_exec_queue *q; 327 327 ··· 798 798 struct xe_vma *vma, *next; 799 799 struct xe_vma_ops vops; 800 800 struct xe_vma_op *op, *next_op; 801 - int err; 801 + int err, i; 802 802 803 803 lockdep_assert_held(&vm->lock); 804 804 if ((xe_vm_in_lr_mode(vm) && !rebind_worker) || ··· 806 806 return 0; 807 807 808 808 xe_vma_ops_init(&vops, vm, NULL, NULL, 0); 809 + for (i = 0; i < XE_MAX_TILES_PER_DEVICE; ++i) 810 + vops.pt_update_ops[i].wait_vm_bookkeep = true; 809 811 810 812 xe_vm_assert_held(vm); 811 813 list_for_each_entry(vma, &vm->rebind_list, combined_links.rebind) { ··· 852 850 struct dma_fence *fence = NULL; 853 851 struct xe_vma_ops vops; 854 852 struct xe_vma_op *op, *next_op; 853 + struct xe_tile *tile; 854 + u8 id; 855 855 int err; 856 856 857 857 lockdep_assert_held(&vm->lock); ··· 861 857 xe_assert(vm->xe, xe_vm_in_fault_mode(vm)); 862 858 863 859 xe_vma_ops_init(&vops, vm, NULL, NULL, 0); 860 + for_each_tile(tile, vm->xe, id) { 861 + vops.pt_update_ops[id].wait_vm_bookkeep = true; 862 + vops.pt_update_ops[tile->id].q = 863 + xe_tile_migrate_exec_queue(tile); 864 + } 864 865 865 866 err = xe_vm_ops_add_rebind(&vops, vma, tile_mask); 866 867 if (err) ··· 1706 1697 return q ? q : vm->q[0]; 1707 1698 } 1708 1699 1709 - static struct dma_fence * 1710 - xe_vm_unbind_vma(struct xe_vma *vma, struct xe_exec_queue *q, 1711 - struct xe_sync_entry *syncs, u32 num_syncs, 1712 - bool first_op, bool last_op) 1713 - { 1714 - struct xe_vm *vm = xe_vma_vm(vma); 1715 - struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, q); 1716 - struct xe_tile *tile; 1717 - struct dma_fence *fence = NULL; 1718 - struct dma_fence **fences = NULL; 1719 - struct dma_fence_array *cf = NULL; 1720 - int cur_fence = 0; 1721 - int number_tiles = hweight8(vma->tile_present); 1722 - int err; 1723 - u8 id; 1724 - 1725 - trace_xe_vma_unbind(vma); 1726 - 1727 - if (number_tiles > 1) { 1728 - fences = kmalloc_array(number_tiles, sizeof(*fences), 1729 - GFP_KERNEL); 1730 - if (!fences) 1731 - return ERR_PTR(-ENOMEM); 1732 - } 1733 - 1734 - for_each_tile(tile, vm->xe, id) { 1735 - if (!(vma->tile_present & BIT(id))) 1736 - goto next; 1737 - 1738 - fence = __xe_pt_unbind_vma(tile, vma, q ? q : vm->q[id], 1739 - first_op ? syncs : NULL, 1740 - first_op ? num_syncs : 0); 1741 - if (IS_ERR(fence)) { 1742 - err = PTR_ERR(fence); 1743 - goto err_fences; 1744 - } 1745 - 1746 - if (fences) 1747 - fences[cur_fence++] = fence; 1748 - 1749 - next: 1750 - if (q && vm->pt_root[id] && !list_empty(&q->multi_gt_list)) 1751 - q = list_next_entry(q, multi_gt_list); 1752 - } 1753 - 1754 - if (fences) { 1755 - cf = dma_fence_array_create(number_tiles, fences, 1756 - vm->composite_fence_ctx, 1757 - vm->composite_fence_seqno++, 1758 - false); 1759 - if (!cf) { 1760 - --vm->composite_fence_seqno; 1761 - err = -ENOMEM; 1762 - goto err_fences; 1763 - } 1764 - } 1765 - 1766 - fence = cf ? &cf->base : !fence ? 1767 - xe_exec_queue_last_fence_get(wait_exec_queue, vm) : fence; 1768 - 1769 - return fence; 1770 - 1771 - err_fences: 1772 - if (fences) { 1773 - while (cur_fence) 1774 - dma_fence_put(fences[--cur_fence]); 1775 - kfree(fences); 1776 - } 1777 - 1778 - return ERR_PTR(err); 1779 - } 1780 - 1781 - static struct dma_fence * 1782 - xe_vm_bind_vma(struct xe_vma *vma, struct xe_exec_queue *q, 1783 - struct xe_sync_entry *syncs, u32 num_syncs, 1784 - u8 tile_mask, bool first_op, bool last_op) 1785 - { 1786 - struct xe_tile *tile; 1787 - struct dma_fence *fence; 1788 - struct dma_fence **fences = NULL; 1789 - struct dma_fence_array *cf = NULL; 1790 - struct xe_vm *vm = xe_vma_vm(vma); 1791 - int cur_fence = 0; 1792 - int number_tiles = hweight8(tile_mask); 1793 - int err; 1794 - u8 id; 1795 - 1796 - trace_xe_vma_bind(vma); 1797 - 1798 - if (number_tiles > 1) { 1799 - fences = kmalloc_array(number_tiles, sizeof(*fences), 1800 - GFP_KERNEL); 1801 - if (!fences) 1802 - return ERR_PTR(-ENOMEM); 1803 - } 1804 - 1805 - for_each_tile(tile, vm->xe, id) { 1806 - if (!(tile_mask & BIT(id))) 1807 - goto next; 1808 - 1809 - fence = __xe_pt_bind_vma(tile, vma, q ? q : vm->q[id], 1810 - first_op ? syncs : NULL, 1811 - first_op ? num_syncs : 0, 1812 - vma->tile_present & BIT(id)); 1813 - if (IS_ERR(fence)) { 1814 - err = PTR_ERR(fence); 1815 - goto err_fences; 1816 - } 1817 - 1818 - if (fences) 1819 - fences[cur_fence++] = fence; 1820 - 1821 - next: 1822 - if (q && vm->pt_root[id] && !list_empty(&q->multi_gt_list)) 1823 - q = list_next_entry(q, multi_gt_list); 1824 - } 1825 - 1826 - if (fences) { 1827 - cf = dma_fence_array_create(number_tiles, fences, 1828 - vm->composite_fence_ctx, 1829 - vm->composite_fence_seqno++, 1830 - false); 1831 - if (!cf) { 1832 - --vm->composite_fence_seqno; 1833 - err = -ENOMEM; 1834 - goto err_fences; 1835 - } 1836 - } 1837 - 1838 - return cf ? &cf->base : fence; 1839 - 1840 - err_fences: 1841 - if (fences) { 1842 - while (cur_fence) 1843 - dma_fence_put(fences[--cur_fence]); 1844 - kfree(fences); 1845 - } 1846 - 1847 - return ERR_PTR(err); 1848 - } 1849 - 1850 1700 static struct xe_user_fence * 1851 1701 find_ufence_get(struct xe_sync_entry *syncs, u32 num_syncs) 1852 1702 { ··· 1719 1851 } 1720 1852 1721 1853 return NULL; 1722 - } 1723 - 1724 - static struct dma_fence * 1725 - xe_vm_bind(struct xe_vm *vm, struct xe_vma *vma, struct xe_exec_queue *q, 1726 - struct xe_bo *bo, struct xe_sync_entry *syncs, u32 num_syncs, 1727 - u8 tile_mask, bool immediate, bool first_op, bool last_op) 1728 - { 1729 - struct dma_fence *fence; 1730 - struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, q); 1731 - 1732 - xe_vm_assert_held(vm); 1733 - xe_bo_assert_held(bo); 1734 - 1735 - if (immediate) { 1736 - fence = xe_vm_bind_vma(vma, q, syncs, num_syncs, tile_mask, 1737 - first_op, last_op); 1738 - if (IS_ERR(fence)) 1739 - return fence; 1740 - } else { 1741 - xe_assert(vm->xe, xe_vm_in_fault_mode(vm)); 1742 - 1743 - fence = xe_exec_queue_last_fence_get(wait_exec_queue, vm); 1744 - } 1745 - 1746 - return fence; 1747 - } 1748 - 1749 - static struct dma_fence * 1750 - xe_vm_unbind(struct xe_vm *vm, struct xe_vma *vma, 1751 - struct xe_exec_queue *q, struct xe_sync_entry *syncs, 1752 - u32 num_syncs, bool first_op, bool last_op) 1753 - { 1754 - struct dma_fence *fence; 1755 - 1756 - xe_vm_assert_held(vm); 1757 - xe_bo_assert_held(xe_vma_bo(vma)); 1758 - 1759 - fence = xe_vm_unbind_vma(vma, q, syncs, num_syncs, first_op, last_op); 1760 - if (IS_ERR(fence)) 1761 - return fence; 1762 - 1763 - return fence; 1764 1854 } 1765 1855 1766 1856 #define ALL_DRM_XE_VM_CREATE_FLAGS (DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE | \ ··· 1860 2034 XE_PL_VRAM0, 1861 2035 XE_PL_VRAM1, 1862 2036 }; 1863 - 1864 - static struct dma_fence * 1865 - xe_vm_prefetch(struct xe_vm *vm, struct xe_vma *vma, 1866 - struct xe_exec_queue *q, struct xe_sync_entry *syncs, 1867 - u32 num_syncs, bool first_op, bool last_op) 1868 - { 1869 - struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, q); 1870 - 1871 - if (vma->tile_mask != (vma->tile_present & ~vma->tile_invalidated)) { 1872 - return xe_vm_bind(vm, vma, q, xe_vma_bo(vma), syncs, num_syncs, 1873 - vma->tile_mask, true, first_op, last_op); 1874 - } else { 1875 - return xe_exec_queue_last_fence_get(wait_exec_queue, vm); 1876 - } 1877 - } 1878 2037 1879 2038 static void prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma, 1880 2039 bool post_commit) ··· 2148 2337 return err; 2149 2338 } 2150 2339 2151 - static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct xe_exec_queue *q, 2152 - struct drm_gpuva_ops *ops, 2153 - struct xe_sync_entry *syncs, u32 num_syncs, 2154 - struct xe_vma_ops *vops, bool last) 2340 + static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops, 2341 + struct xe_vma_ops *vops) 2155 2342 { 2156 2343 struct xe_device *xe = vm->xe; 2157 - struct xe_vma_op *last_op = NULL; 2158 2344 struct drm_gpuva_op *__op; 2159 2345 struct xe_tile *tile; 2160 2346 u8 id, tile_mask = 0; ··· 2165 2357 drm_gpuva_for_each_op(__op, ops) { 2166 2358 struct xe_vma_op *op = gpuva_op_to_vma_op(__op); 2167 2359 struct xe_vma *vma; 2168 - bool first = list_empty(&vops->list); 2169 2360 unsigned int flags = 0; 2170 2361 2171 2362 INIT_LIST_HEAD(&op->link); 2172 2363 list_add_tail(&op->link, &vops->list); 2173 - 2174 - if (first) { 2175 - op->flags |= XE_VMA_OP_FIRST; 2176 - op->num_syncs = num_syncs; 2177 - op->syncs = syncs; 2178 - } 2179 - 2180 - op->q = q; 2181 2364 op->tile_mask = tile_mask; 2182 2365 2183 2366 switch (op->base.op) { ··· 2281 2482 } 2282 2483 case DRM_GPUVA_OP_UNMAP: 2283 2484 case DRM_GPUVA_OP_PREFETCH: 2485 + /* FIXME: Need to skip some prefetch ops */ 2284 2486 xe_vma_ops_incr_pt_update_ops(vops, op->tile_mask); 2285 2487 break; 2286 2488 default: 2287 2489 drm_warn(&vm->xe->drm, "NOT POSSIBLE"); 2288 2490 } 2289 2491 2290 - last_op = op; 2291 - 2292 2492 err = xe_vma_op_commit(vm, op); 2293 2493 if (err) 2294 2494 return err; 2295 2495 } 2296 2496 2297 - /* FIXME: Unhandled corner case */ 2298 - XE_WARN_ON(!last_op && last && !list_empty(&vops->list)); 2299 - 2300 - if (!last_op) 2301 - return 0; 2302 - 2303 - if (last) { 2304 - last_op->flags |= XE_VMA_OP_LAST; 2305 - last_op->num_syncs = num_syncs; 2306 - last_op->syncs = syncs; 2307 - } 2308 - 2309 2497 return 0; 2310 - } 2311 - 2312 - static struct dma_fence *op_execute(struct xe_vm *vm, struct xe_vma *vma, 2313 - struct xe_vma_op *op) 2314 - { 2315 - struct dma_fence *fence = NULL; 2316 - 2317 - lockdep_assert_held(&vm->lock); 2318 - 2319 - xe_vm_assert_held(vm); 2320 - xe_bo_assert_held(xe_vma_bo(vma)); 2321 - 2322 - switch (op->base.op) { 2323 - case DRM_GPUVA_OP_MAP: 2324 - fence = xe_vm_bind(vm, vma, op->q, xe_vma_bo(vma), 2325 - op->syncs, op->num_syncs, 2326 - op->tile_mask, 2327 - op->map.immediate || !xe_vm_in_fault_mode(vm), 2328 - op->flags & XE_VMA_OP_FIRST, 2329 - op->flags & XE_VMA_OP_LAST); 2330 - break; 2331 - case DRM_GPUVA_OP_REMAP: 2332 - { 2333 - bool prev = !!op->remap.prev; 2334 - bool next = !!op->remap.next; 2335 - 2336 - if (!op->remap.unmap_done) { 2337 - if (prev || next) 2338 - vma->gpuva.flags |= XE_VMA_FIRST_REBIND; 2339 - fence = xe_vm_unbind(vm, vma, op->q, op->syncs, 2340 - op->num_syncs, 2341 - op->flags & XE_VMA_OP_FIRST, 2342 - op->flags & XE_VMA_OP_LAST && 2343 - !prev && !next); 2344 - if (IS_ERR(fence)) 2345 - break; 2346 - op->remap.unmap_done = true; 2347 - } 2348 - 2349 - if (prev) { 2350 - op->remap.prev->gpuva.flags |= XE_VMA_LAST_REBIND; 2351 - dma_fence_put(fence); 2352 - fence = xe_vm_bind(vm, op->remap.prev, op->q, 2353 - xe_vma_bo(op->remap.prev), op->syncs, 2354 - op->num_syncs, 2355 - op->remap.prev->tile_mask, true, 2356 - false, 2357 - op->flags & XE_VMA_OP_LAST && !next); 2358 - op->remap.prev->gpuva.flags &= ~XE_VMA_LAST_REBIND; 2359 - if (IS_ERR(fence)) 2360 - break; 2361 - op->remap.prev = NULL; 2362 - } 2363 - 2364 - if (next) { 2365 - op->remap.next->gpuva.flags |= XE_VMA_LAST_REBIND; 2366 - dma_fence_put(fence); 2367 - fence = xe_vm_bind(vm, op->remap.next, op->q, 2368 - xe_vma_bo(op->remap.next), 2369 - op->syncs, op->num_syncs, 2370 - op->remap.next->tile_mask, true, 2371 - false, op->flags & XE_VMA_OP_LAST); 2372 - op->remap.next->gpuva.flags &= ~XE_VMA_LAST_REBIND; 2373 - if (IS_ERR(fence)) 2374 - break; 2375 - op->remap.next = NULL; 2376 - } 2377 - 2378 - break; 2379 - } 2380 - case DRM_GPUVA_OP_UNMAP: 2381 - fence = xe_vm_unbind(vm, vma, op->q, op->syncs, 2382 - op->num_syncs, op->flags & XE_VMA_OP_FIRST, 2383 - op->flags & XE_VMA_OP_LAST); 2384 - break; 2385 - case DRM_GPUVA_OP_PREFETCH: 2386 - fence = xe_vm_prefetch(vm, vma, op->q, op->syncs, op->num_syncs, 2387 - op->flags & XE_VMA_OP_FIRST, 2388 - op->flags & XE_VMA_OP_LAST); 2389 - break; 2390 - default: 2391 - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); 2392 - } 2393 - 2394 - if (IS_ERR(fence)) 2395 - trace_xe_vma_fail(vma); 2396 - 2397 - return fence; 2398 - } 2399 - 2400 - static struct dma_fence * 2401 - __xe_vma_op_execute(struct xe_vm *vm, struct xe_vma *vma, 2402 - struct xe_vma_op *op) 2403 - { 2404 - struct dma_fence *fence; 2405 - int err; 2406 - 2407 - retry_userptr: 2408 - fence = op_execute(vm, vma, op); 2409 - if (IS_ERR(fence) && PTR_ERR(fence) == -EAGAIN) { 2410 - lockdep_assert_held_write(&vm->lock); 2411 - 2412 - if (op->base.op == DRM_GPUVA_OP_REMAP) { 2413 - if (!op->remap.unmap_done) 2414 - vma = gpuva_to_vma(op->base.remap.unmap->va); 2415 - else if (op->remap.prev) 2416 - vma = op->remap.prev; 2417 - else 2418 - vma = op->remap.next; 2419 - } 2420 - 2421 - if (xe_vma_is_userptr(vma)) { 2422 - err = xe_vma_userptr_pin_pages(to_userptr_vma(vma)); 2423 - if (!err) 2424 - goto retry_userptr; 2425 - 2426 - fence = ERR_PTR(err); 2427 - trace_xe_vma_fail(vma); 2428 - } 2429 - } 2430 - 2431 - return fence; 2432 - } 2433 - 2434 - static struct dma_fence * 2435 - xe_vma_op_execute(struct xe_vm *vm, struct xe_vma_op *op) 2436 - { 2437 - struct dma_fence *fence = ERR_PTR(-ENOMEM); 2438 - 2439 - lockdep_assert_held(&vm->lock); 2440 - 2441 - switch (op->base.op) { 2442 - case DRM_GPUVA_OP_MAP: 2443 - fence = __xe_vma_op_execute(vm, op->map.vma, op); 2444 - break; 2445 - case DRM_GPUVA_OP_REMAP: 2446 - { 2447 - struct xe_vma *vma; 2448 - 2449 - if (!op->remap.unmap_done) 2450 - vma = gpuva_to_vma(op->base.remap.unmap->va); 2451 - else if (op->remap.prev) 2452 - vma = op->remap.prev; 2453 - else 2454 - vma = op->remap.next; 2455 - 2456 - fence = __xe_vma_op_execute(vm, vma, op); 2457 - break; 2458 - } 2459 - case DRM_GPUVA_OP_UNMAP: 2460 - fence = __xe_vma_op_execute(vm, gpuva_to_vma(op->base.unmap.va), 2461 - op); 2462 - break; 2463 - case DRM_GPUVA_OP_PREFETCH: 2464 - fence = __xe_vma_op_execute(vm, 2465 - gpuva_to_vma(op->base.prefetch.va), 2466 - op); 2467 - break; 2468 - default: 2469 - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); 2470 - } 2471 - 2472 - return fence; 2473 2498 } 2474 2499 2475 2500 static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op, ··· 2481 2858 return 0; 2482 2859 } 2483 2860 2861 + static int vm_ops_setup_tile_args(struct xe_vm *vm, struct xe_vma_ops *vops) 2862 + { 2863 + struct xe_exec_queue *q = vops->q; 2864 + struct xe_tile *tile; 2865 + int number_tiles = 0; 2866 + u8 id; 2867 + 2868 + for_each_tile(tile, vm->xe, id) { 2869 + if (vops->pt_update_ops[id].num_ops) 2870 + ++number_tiles; 2871 + 2872 + if (vops->pt_update_ops[id].q) 2873 + continue; 2874 + 2875 + if (q) { 2876 + vops->pt_update_ops[id].q = q; 2877 + if (vm->pt_root[id] && !list_empty(&q->multi_gt_list)) 2878 + q = list_next_entry(q, multi_gt_list); 2879 + } else { 2880 + vops->pt_update_ops[id].q = vm->q[id]; 2881 + } 2882 + } 2883 + 2884 + return number_tiles; 2885 + } 2886 + 2484 2887 static struct dma_fence *ops_execute(struct xe_vm *vm, 2485 2888 struct xe_vma_ops *vops) 2486 2889 { 2487 - struct xe_vma_op *op, *next; 2890 + struct xe_tile *tile; 2488 2891 struct dma_fence *fence = NULL; 2892 + struct dma_fence **fences = NULL; 2893 + struct dma_fence_array *cf = NULL; 2894 + int number_tiles = 0, current_fence = 0, err; 2895 + u8 id; 2489 2896 2490 - list_for_each_entry_safe(op, next, &vops->list, link) { 2491 - dma_fence_put(fence); 2492 - fence = xe_vma_op_execute(vm, op); 2493 - if (IS_ERR(fence)) { 2494 - drm_warn(&vm->xe->drm, "VM op(%d) failed with %ld", 2495 - op->base.op, PTR_ERR(fence)); 2496 - fence = ERR_PTR(-ENOSPC); 2497 - break; 2897 + number_tiles = vm_ops_setup_tile_args(vm, vops); 2898 + if (number_tiles == 0) 2899 + return ERR_PTR(-ENODATA); 2900 + 2901 + if (number_tiles > 1) { 2902 + fences = kmalloc_array(number_tiles, sizeof(*fences), 2903 + GFP_KERNEL); 2904 + if (!fences) 2905 + return ERR_PTR(-ENOMEM); 2906 + } 2907 + 2908 + for_each_tile(tile, vm->xe, id) { 2909 + if (!vops->pt_update_ops[id].num_ops) 2910 + continue; 2911 + 2912 + err = xe_pt_update_ops_prepare(tile, vops); 2913 + if (err) { 2914 + fence = ERR_PTR(err); 2915 + goto err_out; 2498 2916 } 2499 2917 } 2918 + 2919 + for_each_tile(tile, vm->xe, id) { 2920 + if (!vops->pt_update_ops[id].num_ops) 2921 + continue; 2922 + 2923 + fence = xe_pt_update_ops_run(tile, vops); 2924 + if (IS_ERR(fence)) 2925 + goto err_out; 2926 + 2927 + if (fences) 2928 + fences[current_fence++] = fence; 2929 + } 2930 + 2931 + if (fences) { 2932 + cf = dma_fence_array_create(number_tiles, fences, 2933 + vm->composite_fence_ctx, 2934 + vm->composite_fence_seqno++, 2935 + false); 2936 + if (!cf) { 2937 + --vm->composite_fence_seqno; 2938 + fence = ERR_PTR(-ENOMEM); 2939 + goto err_out; 2940 + } 2941 + fence = &cf->base; 2942 + } 2943 + 2944 + for_each_tile(tile, vm->xe, id) { 2945 + if (!vops->pt_update_ops[id].num_ops) 2946 + continue; 2947 + 2948 + xe_pt_update_ops_fini(tile, vops); 2949 + } 2950 + 2951 + return fence; 2952 + 2953 + err_out: 2954 + for_each_tile(tile, vm->xe, id) { 2955 + if (!vops->pt_update_ops[id].num_ops) 2956 + continue; 2957 + 2958 + xe_pt_update_ops_abort(tile, vops); 2959 + } 2960 + while (current_fence) 2961 + dma_fence_put(fences[--current_fence]); 2962 + kfree(fences); 2963 + kfree(cf); 2500 2964 2501 2965 return fence; 2502 2966 } ··· 2665 2955 fence = ops_execute(vm, vops); 2666 2956 if (IS_ERR(fence)) { 2667 2957 err = PTR_ERR(fence); 2668 - /* FIXME: Killing VM rather than proper error handling */ 2669 - xe_vm_kill(vm, false); 2670 2958 goto unlock; 2671 - } else { 2672 - vm_bind_ioctl_ops_fini(vm, vops, fence); 2673 2959 } 2960 + 2961 + vm_bind_ioctl_ops_fini(vm, vops, fence); 2674 2962 } 2675 2963 2676 2964 unlock: ··· 3025 3317 goto unwind_ops; 3026 3318 } 3027 3319 3028 - err = vm_bind_ioctl_ops_parse(vm, q, ops[i], syncs, num_syncs, 3029 - &vops, i == args->num_binds - 1); 3320 + err = vm_bind_ioctl_ops_parse(vm, ops[i], &vops); 3030 3321 if (err) 3031 3322 goto unwind_ops; 3032 3323 }
+2
drivers/gpu/drm/xe/xe_vm.h
··· 259 259 return drm_gpuvm_resv(&vm->gpuvm); 260 260 } 261 261 262 + void xe_vm_kill(struct xe_vm *vm, bool unlocked); 263 + 262 264 /** 263 265 * xe_vm_assert_held(vm) - Assert that the vm's reservation object is held. 264 266 * @vm: The vm
+14 -31
drivers/gpu/drm/xe/xe_vm_types.h
··· 26 26 #define XE_VMA_READ_ONLY DRM_GPUVA_USERBITS 27 27 #define XE_VMA_DESTROYED (DRM_GPUVA_USERBITS << 1) 28 28 #define XE_VMA_ATOMIC_PTE_BIT (DRM_GPUVA_USERBITS << 2) 29 - #define XE_VMA_FIRST_REBIND (DRM_GPUVA_USERBITS << 3) 30 - #define XE_VMA_LAST_REBIND (DRM_GPUVA_USERBITS << 4) 31 - #define XE_VMA_PTE_4K (DRM_GPUVA_USERBITS << 5) 32 - #define XE_VMA_PTE_2M (DRM_GPUVA_USERBITS << 6) 33 - #define XE_VMA_PTE_1G (DRM_GPUVA_USERBITS << 7) 34 - #define XE_VMA_PTE_64K (DRM_GPUVA_USERBITS << 8) 35 - #define XE_VMA_PTE_COMPACT (DRM_GPUVA_USERBITS << 9) 36 - #define XE_VMA_DUMPABLE (DRM_GPUVA_USERBITS << 10) 29 + #define XE_VMA_PTE_4K (DRM_GPUVA_USERBITS << 3) 30 + #define XE_VMA_PTE_2M (DRM_GPUVA_USERBITS << 4) 31 + #define XE_VMA_PTE_1G (DRM_GPUVA_USERBITS << 5) 32 + #define XE_VMA_PTE_64K (DRM_GPUVA_USERBITS << 6) 33 + #define XE_VMA_PTE_COMPACT (DRM_GPUVA_USERBITS << 7) 34 + #define XE_VMA_DUMPABLE (DRM_GPUVA_USERBITS << 8) 37 35 38 36 /** struct xe_userptr - User pointer */ 39 37 struct xe_userptr { ··· 97 99 * in write mode. 98 100 */ 99 101 u8 tile_present; 102 + 103 + /** @tile_staged: bind is staged for this VMA */ 104 + u8 tile_staged; 100 105 101 106 /** 102 107 * @pat_index: The pat index to use when encoding the PTEs for this vma. ··· 316 315 317 316 /** enum xe_vma_op_flags - flags for VMA operation */ 318 317 enum xe_vma_op_flags { 319 - /** @XE_VMA_OP_FIRST: first VMA operation for a set of syncs */ 320 - XE_VMA_OP_FIRST = BIT(0), 321 - /** @XE_VMA_OP_LAST: last VMA operation for a set of syncs */ 322 - XE_VMA_OP_LAST = BIT(1), 323 318 /** @XE_VMA_OP_COMMITTED: VMA operation committed */ 324 - XE_VMA_OP_COMMITTED = BIT(2), 319 + XE_VMA_OP_COMMITTED = BIT(0), 325 320 /** @XE_VMA_OP_PREV_COMMITTED: Previous VMA operation committed */ 326 - XE_VMA_OP_PREV_COMMITTED = BIT(3), 321 + XE_VMA_OP_PREV_COMMITTED = BIT(1), 327 322 /** @XE_VMA_OP_NEXT_COMMITTED: Next VMA operation committed */ 328 - XE_VMA_OP_NEXT_COMMITTED = BIT(4), 323 + XE_VMA_OP_NEXT_COMMITTED = BIT(2), 329 324 }; 330 325 331 326 /** struct xe_vma_op - VMA operation */ 332 327 struct xe_vma_op { 333 328 /** @base: GPUVA base operation */ 334 329 struct drm_gpuva_op base; 335 - /** @q: exec queue for this operation */ 336 - struct xe_exec_queue *q; 337 - /** 338 - * @syncs: syncs for this operation, only used on first and last 339 - * operation 340 - */ 341 - struct xe_sync_entry *syncs; 342 - /** @num_syncs: number of syncs */ 343 - u32 num_syncs; 344 330 /** @link: async operation link */ 345 331 struct list_head link; 346 332 /** @flags: operation flags */ ··· 351 363 struct list_head list; 352 364 /** @vm: VM */ 353 365 struct xe_vm *vm; 354 - /** @q: exec queue these operations */ 366 + /** @q: exec queue for VMA operations */ 355 367 struct xe_exec_queue *q; 356 368 /** @syncs: syncs these operation */ 357 369 struct xe_sync_entry *syncs; 358 370 /** @num_syncs: number of syncs */ 359 371 u32 num_syncs; 360 372 /** @pt_update_ops: page table update operations */ 361 - struct { 362 - /** @ops: operations */ 363 - struct xe_vm_pgtable_update_op *ops; 364 - /** @num_ops: number of operations */ 365 - u32 num_ops; 366 - } pt_update_ops[XE_MAX_TILES_PER_DEVICE]; 373 + struct xe_vm_pgtable_update_ops pt_update_ops[XE_MAX_TILES_PER_DEVICE]; 367 374 }; 368 375 369 376 #endif