| .. | .. |
|---|
| 13 | 13 | #include <linux/shmem_fs.h> |
|---|
| 14 | 14 | #include <linux/dma-buf.h> |
|---|
| 15 | 15 | #include <linux/iommu.h> |
|---|
| 16 | | -#include <linux/dma-iommu.h> |
|---|
| 17 | 16 | #include <linux/pfn_t.h> |
|---|
| 18 | 17 | #include <linux/version.h> |
|---|
| 19 | 18 | #include <asm/cacheflush.h> |
|---|
| .. | .. |
|---|
| 68 | 67 | rknpu_obj->size); |
|---|
| 69 | 68 | goto free_sgt; |
|---|
| 70 | 69 | } |
|---|
| 70 | + iommu_flush_iotlb_all(iommu_get_domain_for_dev(drm->dev)); |
|---|
| 71 | 71 | |
|---|
| 72 | 72 | if (rknpu_obj->flags & RKNPU_MEM_KERNEL_MAPPING) { |
|---|
| 73 | 73 | rknpu_obj->cookie = vmap(rknpu_obj->pages, rknpu_obj->num_pages, |
|---|
| .. | .. |
|---|
| 182 | 182 | if (rknpu_obj->flags & RKNPU_MEM_ZEROING) |
|---|
| 183 | 183 | gfp_mask |= __GFP_ZERO; |
|---|
| 184 | 184 | |
|---|
| 185 | | - if (!(rknpu_obj->flags & RKNPU_MEM_NON_DMA32)) { |
|---|
| 185 | + if (!rknpu_dev->iommu_en || |
|---|
| 186 | + rknpu_dev->config->dma_mask <= DMA_BIT_MASK(32) || |
|---|
| 187 | + (rknpu_obj->flags & RKNPU_MEM_DMA32)) { |
|---|
| 186 | 188 | gfp_mask &= ~__GFP_HIGHMEM; |
|---|
| 187 | 189 | gfp_mask |= __GFP_DMA32; |
|---|
| 188 | 190 | } |
|---|
| .. | .. |
|---|
| 253 | 255 | i, &s->dma_address, s->length); |
|---|
| 254 | 256 | } |
|---|
| 255 | 257 | |
|---|
| 256 | | - if (drm_prime_sg_to_page_addr_arrays(sgt, rknpu_obj->pages, NULL, |
|---|
| 257 | | - nr_pages)) { |
|---|
| 258 | | - LOG_DEV_ERROR(drm->dev, "invalid sgtable.\n"); |
|---|
| 259 | | - ret = -EINVAL; |
|---|
| 258 | +#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE |
|---|
| 259 | + ret = drm_prime_sg_to_page_addr_arrays(sgt, rknpu_obj->pages, NULL, |
|---|
| 260 | + nr_pages); |
|---|
| 261 | +#else |
|---|
| 262 | + ret = drm_prime_sg_to_page_array(sgt, rknpu_obj->pages, nr_pages); |
|---|
| 263 | +#endif |
|---|
| 264 | + |
|---|
| 265 | + if (ret < 0) { |
|---|
| 266 | + LOG_DEV_ERROR(drm->dev, "invalid sgtable, ret: %d\n", ret); |
|---|
| 260 | 267 | goto err_free_sg_table; |
|---|
| 261 | 268 | } |
|---|
| 262 | 269 | |
|---|
| .. | .. |
|---|
| 335 | 342 | return drm_gem_handle_delete(file_priv, handle); |
|---|
| 336 | 343 | } |
|---|
| 337 | 344 | |
|---|
| 345 | +#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE |
|---|
| 346 | +static const struct vm_operations_struct vm_ops = { |
|---|
| 347 | + .fault = rknpu_gem_fault, |
|---|
| 348 | + .open = drm_gem_vm_open, |
|---|
| 349 | + .close = drm_gem_vm_close, |
|---|
| 350 | +}; |
|---|
| 351 | + |
|---|
| 352 | +static const struct drm_gem_object_funcs rknpu_gem_object_funcs = { |
|---|
| 353 | + .free = rknpu_gem_free_object, |
|---|
| 354 | + .export = drm_gem_prime_export, |
|---|
| 355 | + .get_sg_table = rknpu_gem_prime_get_sg_table, |
|---|
| 356 | + .vmap = rknpu_gem_prime_vmap, |
|---|
| 357 | + .vunmap = rknpu_gem_prime_vunmap, |
|---|
| 358 | + .mmap = rknpu_gem_mmap_obj, |
|---|
| 359 | + .vm_ops = &vm_ops, |
|---|
| 360 | +}; |
|---|
| 361 | +#endif |
|---|
| 362 | + |
|---|
| 338 | 363 | static struct rknpu_gem_object *rknpu_gem_init(struct drm_device *drm, |
|---|
| 339 | 364 | unsigned long size) |
|---|
| 340 | 365 | { |
|---|
| 366 | + struct rknpu_device *rknpu_dev = drm->dev_private; |
|---|
| 341 | 367 | struct rknpu_gem_object *rknpu_obj = NULL; |
|---|
| 342 | 368 | struct drm_gem_object *obj = NULL; |
|---|
| 343 | 369 | gfp_t gfp_mask; |
|---|
| .. | .. |
|---|
| 348 | 374 | return ERR_PTR(-ENOMEM); |
|---|
| 349 | 375 | |
|---|
| 350 | 376 | obj = &rknpu_obj->base; |
|---|
| 377 | +#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE |
|---|
| 378 | + obj->funcs = &rknpu_gem_object_funcs; |
|---|
| 379 | +#endif |
|---|
| 351 | 380 | |
|---|
| 352 | 381 | ret = drm_gem_object_init(drm, obj, size); |
|---|
| 353 | 382 | if (ret < 0) { |
|---|
| .. | .. |
|---|
| 363 | 392 | if (rknpu_obj->flags & RKNPU_MEM_ZEROING) |
|---|
| 364 | 393 | gfp_mask |= __GFP_ZERO; |
|---|
| 365 | 394 | |
|---|
| 366 | | - if (!(rknpu_obj->flags & RKNPU_MEM_NON_DMA32)) { |
|---|
| 395 | + if (!rknpu_dev->iommu_en || |
|---|
| 396 | + rknpu_dev->config->dma_mask <= DMA_BIT_MASK(32) || |
|---|
| 397 | + (rknpu_obj->flags & RKNPU_MEM_DMA32)) { |
|---|
| 367 | 398 | gfp_mask &= ~__GFP_HIGHMEM; |
|---|
| 368 | 399 | gfp_mask |= __GFP_DMA32; |
|---|
| 369 | 400 | } |
|---|
| .. | .. |
|---|
| 422 | 453 | return -EINVAL; |
|---|
| 423 | 454 | } |
|---|
| 424 | 455 | |
|---|
| 425 | | - cookie = domain->iova_cookie; |
|---|
| 456 | + cookie = (void *)domain->iova_cookie; |
|---|
| 426 | 457 | iovad = &cookie->iovad; |
|---|
| 427 | 458 | rknpu_obj->iova_size = iova_align(iovad, cache_size + rknpu_obj->size); |
|---|
| 428 | 459 | rknpu_obj->iova_start = rknpu_iommu_dma_alloc_iova( |
|---|
| .. | .. |
|---|
| 534 | 565 | iommu_unmap(domain, rknpu_obj->iova_start, cache_size); |
|---|
| 535 | 566 | |
|---|
| 536 | 567 | free_iova: |
|---|
| 537 | | - rknpu_iommu_dma_free_iova(domain->iova_cookie, rknpu_obj->iova_start, |
|---|
| 538 | | - rknpu_obj->iova_size); |
|---|
| 568 | + rknpu_iommu_dma_free_iova((void *)domain->iova_cookie, |
|---|
| 569 | + rknpu_obj->iova_start, rknpu_obj->iova_size); |
|---|
| 539 | 570 | |
|---|
| 540 | 571 | return ret; |
|---|
| 541 | 572 | } |
|---|
| .. | .. |
|---|
| 566 | 597 | if (rknpu_obj->size > 0) |
|---|
| 567 | 598 | iommu_unmap(domain, rknpu_obj->iova_start + cache_size, |
|---|
| 568 | 599 | rknpu_obj->size); |
|---|
| 569 | | - rknpu_iommu_dma_free_iova(domain->iova_cookie, |
|---|
| 600 | + rknpu_iommu_dma_free_iova((void *)domain->iova_cookie, |
|---|
| 570 | 601 | rknpu_obj->iova_start, |
|---|
| 571 | 602 | rknpu_obj->iova_size); |
|---|
| 572 | 603 | } |
|---|
| .. | .. |
|---|
| 954 | 985 | * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map |
|---|
| 955 | 986 | * the whole buffer. |
|---|
| 956 | 987 | */ |
|---|
| 988 | + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP | VM_IO; |
|---|
| 957 | 989 | vma->vm_flags &= ~VM_PFNMAP; |
|---|
| 958 | 990 | vma->vm_pgoff = 0; |
|---|
| 959 | 991 | |
|---|
| .. | .. |
|---|
| 1148 | 1180 | } |
|---|
| 1149 | 1181 | #endif |
|---|
| 1150 | 1182 | |
|---|
| 1151 | | -static int rknpu_gem_mmap_obj(struct drm_gem_object *obj, |
|---|
| 1152 | | - struct vm_area_struct *vma) |
|---|
| 1183 | +int rknpu_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma) |
|---|
| 1153 | 1184 | { |
|---|
| 1154 | 1185 | struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); |
|---|
| 1155 | 1186 | int ret = -EINVAL; |
|---|
| .. | .. |
|---|
| 1246 | 1277 | goto err; |
|---|
| 1247 | 1278 | } |
|---|
| 1248 | 1279 | |
|---|
| 1280 | +#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE |
|---|
| 1249 | 1281 | ret = drm_prime_sg_to_page_addr_arrays(sgt, rknpu_obj->pages, NULL, |
|---|
| 1250 | 1282 | npages); |
|---|
| 1283 | +#else |
|---|
| 1284 | + ret = drm_prime_sg_to_page_array(sgt, rknpu_obj->pages, npages); |
|---|
| 1285 | +#endif |
|---|
| 1251 | 1286 | if (ret < 0) |
|---|
| 1252 | 1287 | goto err_free_large; |
|---|
| 1253 | 1288 | |
|---|
| .. | .. |
|---|
| 1275 | 1310 | return ERR_PTR(ret); |
|---|
| 1276 | 1311 | } |
|---|
| 1277 | 1312 | |
|---|
| 1313 | +#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE |
|---|
| 1278 | 1314 | void *rknpu_gem_prime_vmap(struct drm_gem_object *obj) |
|---|
| 1279 | 1315 | { |
|---|
| 1280 | 1316 | struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); |
|---|
| .. | .. |
|---|
| 1290 | 1326 | { |
|---|
| 1291 | 1327 | vunmap(vaddr); |
|---|
| 1292 | 1328 | } |
|---|
| 1329 | +#else |
|---|
| 1330 | +int rknpu_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) |
|---|
| 1331 | +{ |
|---|
| 1332 | + struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); |
|---|
| 1333 | + void *vaddr = NULL; |
|---|
| 1334 | + |
|---|
| 1335 | + if (!rknpu_obj->pages) |
|---|
| 1336 | + return -EINVAL; |
|---|
| 1337 | + |
|---|
| 1338 | + vaddr = vmap(rknpu_obj->pages, rknpu_obj->num_pages, VM_MAP, |
|---|
| 1339 | + PAGE_KERNEL); |
|---|
| 1340 | + if (!vaddr) |
|---|
| 1341 | + return -ENOMEM; |
|---|
| 1342 | + |
|---|
| 1343 | + iosys_map_set_vaddr(map, vaddr); |
|---|
| 1344 | + |
|---|
| 1345 | + return 0; |
|---|
| 1346 | +} |
|---|
| 1347 | + |
|---|
| 1348 | +void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) |
|---|
| 1349 | +{ |
|---|
| 1350 | + struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); |
|---|
| 1351 | + |
|---|
| 1352 | + if (rknpu_obj->pages) { |
|---|
| 1353 | + vunmap(map->vaddr); |
|---|
| 1354 | + map->vaddr = NULL; |
|---|
| 1355 | + } |
|---|
| 1356 | +} |
|---|
| 1357 | +#endif |
|---|
| 1293 | 1358 | |
|---|
| 1294 | 1359 | int rknpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) |
|---|
| 1295 | 1360 | { |
|---|
| .. | .. |
|---|
| 1306 | 1371 | unsigned long *length, unsigned long *offset, |
|---|
| 1307 | 1372 | enum rknpu_cache_type cache_type) |
|---|
| 1308 | 1373 | { |
|---|
| 1374 | +#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE |
|---|
| 1309 | 1375 | struct drm_gem_object *obj = &rknpu_obj->base; |
|---|
| 1310 | 1376 | struct rknpu_device *rknpu_dev = obj->dev->dev_private; |
|---|
| 1311 | 1377 | void __iomem *cache_base_io = NULL; |
|---|
| .. | .. |
|---|
| 1348 | 1414 | *length -= cache_length; |
|---|
| 1349 | 1415 | *offset = 0; |
|---|
| 1350 | 1416 | } |
|---|
| 1417 | +#endif |
|---|
| 1418 | + |
|---|
| 1351 | 1419 | return 0; |
|---|
| 1352 | 1420 | } |
|---|
| 1353 | 1421 | |
|---|
| .. | .. |
|---|
| 1355 | 1423 | struct drm_file *file_priv) |
|---|
| 1356 | 1424 | { |
|---|
| 1357 | 1425 | struct rknpu_gem_object *rknpu_obj = NULL; |
|---|
| 1426 | + struct rknpu_device *rknpu_dev = dev->dev_private; |
|---|
| 1358 | 1427 | struct rknpu_mem_sync *args = data; |
|---|
| 1359 | 1428 | struct scatterlist *sg; |
|---|
| 1429 | + dma_addr_t sg_phys_addr; |
|---|
| 1360 | 1430 | unsigned long length, offset = 0; |
|---|
| 1361 | | - unsigned long sg_left, size = 0; |
|---|
| 1431 | + unsigned long sg_offset, sg_left, size = 0; |
|---|
| 1362 | 1432 | unsigned long len = 0; |
|---|
| 1363 | 1433 | int i; |
|---|
| 1364 | 1434 | |
|---|
| .. | .. |
|---|
| 1382 | 1452 | DMA_FROM_DEVICE); |
|---|
| 1383 | 1453 | } |
|---|
| 1384 | 1454 | } else { |
|---|
| 1455 | + WARN_ON(!rknpu_dev->fake_dev); |
|---|
| 1456 | + |
|---|
| 1385 | 1457 | length = args->size; |
|---|
| 1386 | 1458 | offset = args->offset; |
|---|
| 1387 | 1459 | |
|---|
| .. | .. |
|---|
| 1405 | 1477 | if (len <= offset) |
|---|
| 1406 | 1478 | continue; |
|---|
| 1407 | 1479 | |
|---|
| 1480 | + sg_phys_addr = sg_phys(sg); |
|---|
| 1481 | + |
|---|
| 1408 | 1482 | sg_left = len - offset; |
|---|
| 1483 | + sg_offset = sg->length - sg_left; |
|---|
| 1484 | + |
|---|
| 1409 | 1485 | size = (length < sg_left) ? length : sg_left; |
|---|
| 1410 | 1486 | |
|---|
| 1411 | 1487 | if (args->flags & RKNPU_MEM_SYNC_TO_DEVICE) { |
|---|
| 1412 | | - dma_sync_sg_for_device(dev->dev, sg, 1, |
|---|
| 1413 | | - DMA_TO_DEVICE); |
|---|
| 1488 | + dma_sync_single_range_for_device( |
|---|
| 1489 | + rknpu_dev->fake_dev, sg_phys_addr, |
|---|
| 1490 | + sg_offset, size, DMA_TO_DEVICE); |
|---|
| 1414 | 1491 | } |
|---|
| 1415 | 1492 | |
|---|
| 1416 | 1493 | if (args->flags & RKNPU_MEM_SYNC_FROM_DEVICE) { |
|---|
| 1417 | | - dma_sync_sg_for_cpu(dev->dev, sg, 1, |
|---|
| 1418 | | - DMA_FROM_DEVICE); |
|---|
| 1494 | + dma_sync_single_range_for_cpu( |
|---|
| 1495 | + rknpu_dev->fake_dev, sg_phys_addr, |
|---|
| 1496 | + sg_offset, size, DMA_FROM_DEVICE); |
|---|
| 1419 | 1497 | } |
|---|
| 1420 | 1498 | |
|---|
| 1421 | 1499 | offset += size; |
|---|