| .. | .. |
|---|
| 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> |
|---|
| .. | .. |
|---|
| 25 | 24 | #include "rknpu_drv.h" |
|---|
| 26 | 25 | #include "rknpu_ioctl.h" |
|---|
| 27 | 26 | #include "rknpu_gem.h" |
|---|
| 27 | +#include "rknpu_iommu.h" |
|---|
| 28 | 28 | |
|---|
| 29 | 29 | #define RKNPU_GEM_ALLOC_FROM_PAGES 1 |
|---|
| 30 | 30 | |
|---|
| .. | .. |
|---|
| 67 | 67 | rknpu_obj->size); |
|---|
| 68 | 68 | goto free_sgt; |
|---|
| 69 | 69 | } |
|---|
| 70 | + iommu_flush_iotlb_all(iommu_get_domain_for_dev(drm->dev)); |
|---|
| 70 | 71 | |
|---|
| 71 | 72 | if (rknpu_obj->flags & RKNPU_MEM_KERNEL_MAPPING) { |
|---|
| 72 | 73 | rknpu_obj->cookie = vmap(rknpu_obj->pages, rknpu_obj->num_pages, |
|---|
| .. | .. |
|---|
| 115 | 116 | rknpu_obj->kv_addr = NULL; |
|---|
| 116 | 117 | } |
|---|
| 117 | 118 | |
|---|
| 118 | | - dma_unmap_sg(drm->dev, rknpu_obj->sgt->sgl, rknpu_obj->sgt->nents, |
|---|
| 119 | | - DMA_BIDIRECTIONAL); |
|---|
| 120 | | - |
|---|
| 121 | | - drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, true, true); |
|---|
| 122 | | - |
|---|
| 123 | 119 | if (rknpu_obj->sgt != NULL) { |
|---|
| 120 | + dma_unmap_sg(drm->dev, rknpu_obj->sgt->sgl, |
|---|
| 121 | + rknpu_obj->sgt->nents, DMA_BIDIRECTIONAL); |
|---|
| 124 | 122 | sg_free_table(rknpu_obj->sgt); |
|---|
| 125 | 123 | kfree(rknpu_obj->sgt); |
|---|
| 126 | 124 | } |
|---|
| 125 | + |
|---|
| 126 | + drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, true, true); |
|---|
| 127 | 127 | } |
|---|
| 128 | 128 | #endif |
|---|
| 129 | 129 | |
|---|
| .. | .. |
|---|
| 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 | } |
|---|
| .. | .. |
|---|
| 380 | 411 | kfree(rknpu_obj); |
|---|
| 381 | 412 | } |
|---|
| 382 | 413 | |
|---|
| 383 | | -static int rknpu_gem_alloc_buf_with_sram(struct rknpu_gem_object *rknpu_obj) |
|---|
| 414 | +static int rknpu_gem_alloc_buf_with_cache(struct rknpu_gem_object *rknpu_obj, |
|---|
| 415 | + enum rknpu_cache_type cache_type) |
|---|
| 384 | 416 | { |
|---|
| 385 | 417 | struct drm_device *drm = rknpu_obj->base.dev; |
|---|
| 386 | 418 | struct rknpu_device *rknpu_dev = drm->dev_private; |
|---|
| .. | .. |
|---|
| 393 | 425 | unsigned long offset = 0; |
|---|
| 394 | 426 | int i = 0; |
|---|
| 395 | 427 | int ret = -EINVAL; |
|---|
| 428 | + phys_addr_t cache_start = 0; |
|---|
| 429 | + unsigned long cache_offset = 0; |
|---|
| 430 | + unsigned long cache_size = 0; |
|---|
| 396 | 431 | |
|---|
| 397 | | - /* iova map to sram */ |
|---|
| 432 | + switch (cache_type) { |
|---|
| 433 | + case RKNPU_CACHE_SRAM: |
|---|
| 434 | + cache_start = rknpu_dev->sram_start; |
|---|
| 435 | + cache_offset = rknpu_obj->sram_obj->range_start * |
|---|
| 436 | + rknpu_dev->sram_mm->chunk_size; |
|---|
| 437 | + cache_size = rknpu_obj->sram_size; |
|---|
| 438 | + break; |
|---|
| 439 | + case RKNPU_CACHE_NBUF: |
|---|
| 440 | + cache_start = rknpu_dev->nbuf_start; |
|---|
| 441 | + cache_offset = 0; |
|---|
| 442 | + cache_size = rknpu_obj->nbuf_size; |
|---|
| 443 | + break; |
|---|
| 444 | + default: |
|---|
| 445 | + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); |
|---|
| 446 | + return -EINVAL; |
|---|
| 447 | + } |
|---|
| 448 | + |
|---|
| 449 | + /* iova map to cache */ |
|---|
| 398 | 450 | domain = iommu_get_domain_for_dev(rknpu_dev->dev); |
|---|
| 399 | 451 | if (!domain) { |
|---|
| 400 | 452 | LOG_ERROR("failed to get iommu domain!"); |
|---|
| 401 | 453 | return -EINVAL; |
|---|
| 402 | 454 | } |
|---|
| 403 | 455 | |
|---|
| 404 | | - cookie = domain->iova_cookie; |
|---|
| 456 | + cookie = (void *)domain->iova_cookie; |
|---|
| 405 | 457 | iovad = &cookie->iovad; |
|---|
| 406 | | - rknpu_obj->iova_size = |
|---|
| 407 | | - iova_align(iovad, rknpu_obj->sram_size + rknpu_obj->size); |
|---|
| 458 | + rknpu_obj->iova_size = iova_align(iovad, cache_size + rknpu_obj->size); |
|---|
| 408 | 459 | rknpu_obj->iova_start = rknpu_iommu_dma_alloc_iova( |
|---|
| 409 | 460 | domain, rknpu_obj->iova_size, dma_get_mask(drm->dev), drm->dev); |
|---|
| 410 | 461 | if (!rknpu_obj->iova_start) { |
|---|
| .. | .. |
|---|
| 416 | 467 | &rknpu_obj->iova_start, rknpu_obj->iova_size); |
|---|
| 417 | 468 | |
|---|
| 418 | 469 | /* |
|---|
| 419 | | - * Overview SRAM + DDR map to IOVA |
|---|
| 470 | + * Overview cache + DDR map to IOVA |
|---|
| 420 | 471 | * -------- |
|---|
| 421 | | - * sram_size: rknpu_obj->sram_size |
|---|
| 422 | | - * - allocate from SRAM, this size value has been page-aligned |
|---|
| 472 | + * cache_size: |
|---|
| 473 | + * - allocate from CACHE, this size value has been page-aligned |
|---|
| 423 | 474 | * size: rknpu_obj->size |
|---|
| 424 | 475 | * - allocate from DDR pages, this size value has been page-aligned |
|---|
| 425 | 476 | * iova_size: rknpu_obj->iova_size |
|---|
| 426 | | - * - from iova_align(sram_size + size) |
|---|
| 427 | | - * - it may be larger than the (sram_size + size), and the larger part is not mapped |
|---|
| 477 | + * - from iova_align(cache_size + size) |
|---|
| 478 | + * - it may be larger than the (cache_size + size), and the larger part is not mapped |
|---|
| 428 | 479 | * -------- |
|---|
| 429 | 480 | * |
|---|
| 430 | | - * |<- sram_size ->| |<- - - - size - - - ->| |
|---|
| 481 | + * |<- cache_size ->| |<- - - - size - - - ->| |
|---|
| 431 | 482 | * +---------------+ +----------------------+ |
|---|
| 432 | | - * | SRAM | | DDR | |
|---|
| 483 | + * | CACHE | | DDR | |
|---|
| 433 | 484 | * +---------------+ +----------------------+ |
|---|
| 434 | 485 | * | | |
|---|
| 435 | 486 | * | V | V | |
|---|
| .. | .. |
|---|
| 439 | 490 | * |<- - - - - - - iova_size - - - - - - ->| |
|---|
| 440 | 491 | * |
|---|
| 441 | 492 | */ |
|---|
| 442 | | - offset = rknpu_obj->sram_obj->range_start * |
|---|
| 443 | | - rknpu_dev->sram_mm->chunk_size; |
|---|
| 444 | 493 | ret = iommu_map(domain, rknpu_obj->iova_start, |
|---|
| 445 | | - rknpu_dev->sram_start + offset, rknpu_obj->sram_size, |
|---|
| 494 | + cache_start + cache_offset, cache_size, |
|---|
| 446 | 495 | IOMMU_READ | IOMMU_WRITE); |
|---|
| 447 | 496 | if (ret) { |
|---|
| 448 | | - LOG_ERROR("sram iommu_map error: %d\n", ret); |
|---|
| 497 | + LOG_ERROR("cache iommu_map error: %d\n", ret); |
|---|
| 449 | 498 | goto free_iova; |
|---|
| 450 | 499 | } |
|---|
| 451 | 500 | |
|---|
| 452 | 501 | rknpu_obj->dma_addr = rknpu_obj->iova_start; |
|---|
| 453 | 502 | |
|---|
| 454 | 503 | if (rknpu_obj->size == 0) { |
|---|
| 455 | | - LOG_INFO("allocate sram size: %lu\n", rknpu_obj->sram_size); |
|---|
| 504 | + LOG_INFO("allocate cache size: %lu\n", cache_size); |
|---|
| 456 | 505 | return 0; |
|---|
| 457 | 506 | } |
|---|
| 458 | 507 | |
|---|
| .. | .. |
|---|
| 460 | 509 | if (IS_ERR(rknpu_obj->pages)) { |
|---|
| 461 | 510 | ret = PTR_ERR(rknpu_obj->pages); |
|---|
| 462 | 511 | LOG_ERROR("failed to get pages: %d\n", ret); |
|---|
| 463 | | - goto sram_unmap; |
|---|
| 512 | + goto cache_unmap; |
|---|
| 464 | 513 | } |
|---|
| 465 | 514 | |
|---|
| 466 | 515 | rknpu_obj->num_pages = rknpu_obj->size >> PAGE_SHIFT; |
|---|
| .. | .. |
|---|
| 479 | 528 | } |
|---|
| 480 | 529 | |
|---|
| 481 | 530 | length = rknpu_obj->size; |
|---|
| 482 | | - offset = rknpu_obj->iova_start + rknpu_obj->sram_size; |
|---|
| 531 | + offset = rknpu_obj->iova_start + cache_size; |
|---|
| 483 | 532 | |
|---|
| 484 | 533 | for_each_sg(rknpu_obj->sgt->sgl, s, rknpu_obj->sgt->nents, i) { |
|---|
| 485 | 534 | size = (length < s->length) ? length : s->length; |
|---|
| .. | .. |
|---|
| 498 | 547 | break; |
|---|
| 499 | 548 | } |
|---|
| 500 | 549 | |
|---|
| 501 | | - LOG_INFO("allocate size: %lu with sram size: %lu\n", rknpu_obj->size, |
|---|
| 502 | | - rknpu_obj->sram_size); |
|---|
| 550 | + LOG_INFO("allocate size: %lu with cache size: %lu\n", rknpu_obj->size, |
|---|
| 551 | + cache_size); |
|---|
| 503 | 552 | |
|---|
| 504 | 553 | return 0; |
|---|
| 505 | 554 | |
|---|
| 506 | 555 | sgl_unmap: |
|---|
| 507 | | - iommu_unmap(domain, rknpu_obj->iova_start + rknpu_obj->sram_size, |
|---|
| 556 | + iommu_unmap(domain, rknpu_obj->iova_start + cache_size, |
|---|
| 508 | 557 | rknpu_obj->size - length); |
|---|
| 509 | 558 | sg_free_table(rknpu_obj->sgt); |
|---|
| 510 | 559 | kfree(rknpu_obj->sgt); |
|---|
| .. | .. |
|---|
| 512 | 561 | put_pages: |
|---|
| 513 | 562 | drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, false, false); |
|---|
| 514 | 563 | |
|---|
| 515 | | -sram_unmap: |
|---|
| 516 | | - iommu_unmap(domain, rknpu_obj->iova_start, rknpu_obj->sram_size); |
|---|
| 564 | +cache_unmap: |
|---|
| 565 | + iommu_unmap(domain, rknpu_obj->iova_start, cache_size); |
|---|
| 517 | 566 | |
|---|
| 518 | 567 | free_iova: |
|---|
| 519 | | - rknpu_iommu_dma_free_iova(domain->iova_cookie, rknpu_obj->iova_start, |
|---|
| 520 | | - rknpu_obj->iova_size); |
|---|
| 568 | + rknpu_iommu_dma_free_iova((void *)domain->iova_cookie, |
|---|
| 569 | + rknpu_obj->iova_start, rknpu_obj->iova_size); |
|---|
| 521 | 570 | |
|---|
| 522 | 571 | return ret; |
|---|
| 523 | 572 | } |
|---|
| 524 | 573 | |
|---|
| 525 | | -static void rknpu_gem_free_buf_with_sram(struct rknpu_gem_object *rknpu_obj) |
|---|
| 574 | +static void rknpu_gem_free_buf_with_cache(struct rknpu_gem_object *rknpu_obj, |
|---|
| 575 | + enum rknpu_cache_type cache_type) |
|---|
| 526 | 576 | { |
|---|
| 527 | 577 | struct drm_device *drm = rknpu_obj->base.dev; |
|---|
| 528 | 578 | struct rknpu_device *rknpu_dev = drm->dev_private; |
|---|
| 529 | 579 | struct iommu_domain *domain = NULL; |
|---|
| 580 | + unsigned long cache_size = 0; |
|---|
| 581 | + |
|---|
| 582 | + switch (cache_type) { |
|---|
| 583 | + case RKNPU_CACHE_SRAM: |
|---|
| 584 | + cache_size = rknpu_obj->sram_size; |
|---|
| 585 | + break; |
|---|
| 586 | + case RKNPU_CACHE_NBUF: |
|---|
| 587 | + cache_size = rknpu_obj->nbuf_size; |
|---|
| 588 | + break; |
|---|
| 589 | + default: |
|---|
| 590 | + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); |
|---|
| 591 | + return; |
|---|
| 592 | + } |
|---|
| 530 | 593 | |
|---|
| 531 | 594 | domain = iommu_get_domain_for_dev(rknpu_dev->dev); |
|---|
| 532 | 595 | if (domain) { |
|---|
| 533 | | - iommu_unmap(domain, rknpu_obj->iova_start, |
|---|
| 534 | | - rknpu_obj->sram_size); |
|---|
| 596 | + iommu_unmap(domain, rknpu_obj->iova_start, cache_size); |
|---|
| 535 | 597 | if (rknpu_obj->size > 0) |
|---|
| 536 | | - iommu_unmap(domain, |
|---|
| 537 | | - rknpu_obj->iova_start + |
|---|
| 538 | | - rknpu_obj->sram_size, |
|---|
| 598 | + iommu_unmap(domain, rknpu_obj->iova_start + cache_size, |
|---|
| 539 | 599 | rknpu_obj->size); |
|---|
| 540 | | - rknpu_iommu_dma_free_iova(domain->iova_cookie, |
|---|
| 600 | + rknpu_iommu_dma_free_iova((void *)domain->iova_cookie, |
|---|
| 541 | 601 | rknpu_obj->iova_start, |
|---|
| 542 | 602 | rknpu_obj->iova_size); |
|---|
| 543 | 603 | } |
|---|
| .. | .. |
|---|
| 618 | 678 | if (real_sram_size > 0) { |
|---|
| 619 | 679 | rknpu_obj->sram_size = real_sram_size; |
|---|
| 620 | 680 | |
|---|
| 621 | | - ret = rknpu_gem_alloc_buf_with_sram(rknpu_obj); |
|---|
| 681 | + ret = rknpu_gem_alloc_buf_with_cache(rknpu_obj, |
|---|
| 682 | + RKNPU_CACHE_SRAM); |
|---|
| 622 | 683 | if (ret < 0) |
|---|
| 623 | 684 | goto mm_free; |
|---|
| 685 | + remain_ddr_size = 0; |
|---|
| 686 | + } |
|---|
| 687 | + } else if (IS_ENABLED(CONFIG_NO_GKI) && |
|---|
| 688 | + (flags & RKNPU_MEM_TRY_ALLOC_NBUF) && |
|---|
| 689 | + rknpu_dev->nbuf_size > 0) { |
|---|
| 690 | + size_t nbuf_size = 0; |
|---|
| 691 | + |
|---|
| 692 | + rknpu_obj = rknpu_gem_init(drm, remain_ddr_size); |
|---|
| 693 | + if (IS_ERR(rknpu_obj)) |
|---|
| 694 | + return rknpu_obj; |
|---|
| 695 | + |
|---|
| 696 | + nbuf_size = remain_ddr_size <= rknpu_dev->nbuf_size ? |
|---|
| 697 | + remain_ddr_size : |
|---|
| 698 | + rknpu_dev->nbuf_size; |
|---|
| 699 | + |
|---|
| 700 | + /* set memory type and cache attribute from user side. */ |
|---|
| 701 | + rknpu_obj->flags = flags; |
|---|
| 702 | + |
|---|
| 703 | + if (nbuf_size > 0) { |
|---|
| 704 | + rknpu_obj->nbuf_size = nbuf_size; |
|---|
| 705 | + |
|---|
| 706 | + ret = rknpu_gem_alloc_buf_with_cache(rknpu_obj, |
|---|
| 707 | + RKNPU_CACHE_NBUF); |
|---|
| 708 | + if (ret < 0) |
|---|
| 709 | + goto gem_release; |
|---|
| 624 | 710 | remain_ddr_size = 0; |
|---|
| 625 | 711 | } |
|---|
| 626 | 712 | } |
|---|
| .. | .. |
|---|
| 640 | 726 | |
|---|
| 641 | 727 | if (rknpu_obj) |
|---|
| 642 | 728 | LOG_DEBUG( |
|---|
| 643 | | - "created dma addr: %pad, cookie: %p, ddr size: %lu, sram size: %lu, attrs: %#lx, flags: %#x\n", |
|---|
| 644 | | - &rknpu_obj->dma_addr, rknpu_obj->cookie, rknpu_obj->size, |
|---|
| 645 | | - rknpu_obj->sram_size, rknpu_obj->dma_attrs, rknpu_obj->flags); |
|---|
| 729 | + "created dma addr: %pad, cookie: %p, ddr size: %lu, sram size: %lu, nbuf size: %lu, attrs: %#lx, flags: %#x\n", |
|---|
| 730 | + &rknpu_obj->dma_addr, rknpu_obj->cookie, |
|---|
| 731 | + rknpu_obj->size, rknpu_obj->sram_size, |
|---|
| 732 | + rknpu_obj->nbuf_size, rknpu_obj->dma_attrs, |
|---|
| 733 | + rknpu_obj->flags); |
|---|
| 646 | 734 | |
|---|
| 647 | 735 | return rknpu_obj; |
|---|
| 648 | 736 | |
|---|
| .. | .. |
|---|
| 683 | 771 | if (rknpu_obj->sram_obj != NULL) |
|---|
| 684 | 772 | rknpu_mm_free(rknpu_dev->sram_mm, |
|---|
| 685 | 773 | rknpu_obj->sram_obj); |
|---|
| 686 | | - rknpu_gem_free_buf_with_sram(rknpu_obj); |
|---|
| 774 | + rknpu_gem_free_buf_with_cache(rknpu_obj, |
|---|
| 775 | + RKNPU_CACHE_SRAM); |
|---|
| 776 | + } else if (IS_ENABLED(CONFIG_NO_GKI) && |
|---|
| 777 | + rknpu_obj->nbuf_size > 0) { |
|---|
| 778 | + rknpu_gem_free_buf_with_cache(rknpu_obj, |
|---|
| 779 | + RKNPU_CACHE_NBUF); |
|---|
| 687 | 780 | } else { |
|---|
| 688 | 781 | rknpu_gem_free_buf(rknpu_obj); |
|---|
| 689 | 782 | } |
|---|
| .. | .. |
|---|
| 808 | 901 | } |
|---|
| 809 | 902 | #endif |
|---|
| 810 | 903 | |
|---|
| 904 | +static int rknpu_gem_mmap_cache(struct rknpu_gem_object *rknpu_obj, |
|---|
| 905 | + struct vm_area_struct *vma, |
|---|
| 906 | + enum rknpu_cache_type cache_type) |
|---|
| 907 | +{ |
|---|
| 908 | + struct drm_device *drm = rknpu_obj->base.dev; |
|---|
| 909 | +#if RKNPU_GEM_ALLOC_FROM_PAGES |
|---|
| 910 | + struct rknpu_device *rknpu_dev = drm->dev_private; |
|---|
| 911 | +#endif |
|---|
| 912 | + unsigned long vm_size = 0; |
|---|
| 913 | + int ret = -EINVAL; |
|---|
| 914 | + unsigned long offset = 0; |
|---|
| 915 | + unsigned long num_pages = 0; |
|---|
| 916 | + int i = 0; |
|---|
| 917 | + phys_addr_t cache_start = 0; |
|---|
| 918 | + unsigned long cache_offset = 0; |
|---|
| 919 | + unsigned long cache_size = 0; |
|---|
| 920 | + |
|---|
| 921 | + switch (cache_type) { |
|---|
| 922 | + case RKNPU_CACHE_SRAM: |
|---|
| 923 | + cache_start = rknpu_dev->sram_start; |
|---|
| 924 | + cache_offset = rknpu_obj->sram_obj->range_start * |
|---|
| 925 | + rknpu_dev->sram_mm->chunk_size; |
|---|
| 926 | + cache_size = rknpu_obj->sram_size; |
|---|
| 927 | + break; |
|---|
| 928 | + case RKNPU_CACHE_NBUF: |
|---|
| 929 | + cache_start = rknpu_dev->nbuf_start; |
|---|
| 930 | + cache_offset = 0; |
|---|
| 931 | + cache_size = rknpu_obj->nbuf_size; |
|---|
| 932 | + break; |
|---|
| 933 | + default: |
|---|
| 934 | + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); |
|---|
| 935 | + return -EINVAL; |
|---|
| 936 | + } |
|---|
| 937 | + |
|---|
| 938 | + vma->vm_flags |= VM_MIXEDMAP; |
|---|
| 939 | + |
|---|
| 940 | + vm_size = vma->vm_end - vma->vm_start; |
|---|
| 941 | + |
|---|
| 942 | + /* |
|---|
| 943 | + * Convert a physical address in a cache area to a page frame number (PFN), |
|---|
| 944 | + * and store the resulting PFN in the vm_pgoff field of the given VMA. |
|---|
| 945 | + * |
|---|
| 946 | + * NOTE: This conversion carries a risk because the resulting PFN is not a true |
|---|
| 947 | + * page frame number and may not be valid or usable in all contexts. |
|---|
| 948 | + */ |
|---|
| 949 | + vma->vm_pgoff = __phys_to_pfn(cache_start + cache_offset); |
|---|
| 950 | + |
|---|
| 951 | + ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, cache_size, |
|---|
| 952 | + vma->vm_page_prot); |
|---|
| 953 | + if (ret) |
|---|
| 954 | + return -EAGAIN; |
|---|
| 955 | + |
|---|
| 956 | + if (rknpu_obj->size == 0) |
|---|
| 957 | + return 0; |
|---|
| 958 | + |
|---|
| 959 | + offset = cache_size; |
|---|
| 960 | + |
|---|
| 961 | + num_pages = (vm_size - cache_size) / PAGE_SIZE; |
|---|
| 962 | + for (i = 0; i < num_pages; ++i) { |
|---|
| 963 | + ret = vm_insert_page(vma, vma->vm_start + offset, |
|---|
| 964 | + rknpu_obj->pages[i]); |
|---|
| 965 | + if (ret < 0) |
|---|
| 966 | + return ret; |
|---|
| 967 | + offset += PAGE_SIZE; |
|---|
| 968 | + } |
|---|
| 969 | + |
|---|
| 970 | + return 0; |
|---|
| 971 | +} |
|---|
| 972 | + |
|---|
| 811 | 973 | static int rknpu_gem_mmap_buffer(struct rknpu_gem_object *rknpu_obj, |
|---|
| 812 | 974 | struct vm_area_struct *vma) |
|---|
| 813 | 975 | { |
|---|
| .. | .. |
|---|
| 823 | 985 | * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map |
|---|
| 824 | 986 | * the whole buffer. |
|---|
| 825 | 987 | */ |
|---|
| 988 | + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP | VM_IO; |
|---|
| 826 | 989 | vma->vm_flags &= ~VM_PFNMAP; |
|---|
| 827 | 990 | vma->vm_pgoff = 0; |
|---|
| 828 | 991 | |
|---|
| .. | .. |
|---|
| 832 | 995 | if (vm_size > rknpu_obj->size) |
|---|
| 833 | 996 | return -EINVAL; |
|---|
| 834 | 997 | |
|---|
| 835 | | - if (rknpu_obj->sram_size > 0) { |
|---|
| 836 | | - unsigned long offset = 0; |
|---|
| 837 | | - unsigned long num_pages = 0; |
|---|
| 838 | | - int i = 0; |
|---|
| 839 | | - |
|---|
| 840 | | - vma->vm_flags |= VM_MIXEDMAP; |
|---|
| 841 | | - |
|---|
| 842 | | - offset = rknpu_obj->sram_obj->range_start * |
|---|
| 843 | | - rknpu_dev->sram_mm->chunk_size; |
|---|
| 844 | | - vma->vm_pgoff = __phys_to_pfn(rknpu_dev->sram_start + offset); |
|---|
| 845 | | - |
|---|
| 846 | | - ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, |
|---|
| 847 | | - rknpu_obj->sram_size, vma->vm_page_prot); |
|---|
| 848 | | - if (ret) |
|---|
| 849 | | - return -EAGAIN; |
|---|
| 850 | | - |
|---|
| 851 | | - if (rknpu_obj->size == 0) |
|---|
| 852 | | - return 0; |
|---|
| 853 | | - |
|---|
| 854 | | - offset = rknpu_obj->sram_size; |
|---|
| 855 | | - |
|---|
| 856 | | - num_pages = (vm_size - rknpu_obj->sram_size) / PAGE_SIZE; |
|---|
| 857 | | - for (i = 0; i < num_pages; ++i) { |
|---|
| 858 | | - ret = vm_insert_page(vma, vma->vm_start + offset, |
|---|
| 859 | | - rknpu_obj->pages[i]); |
|---|
| 860 | | - if (ret < 0) |
|---|
| 861 | | - return ret; |
|---|
| 862 | | - offset += PAGE_SIZE; |
|---|
| 863 | | - } |
|---|
| 864 | | - |
|---|
| 865 | | - return 0; |
|---|
| 866 | | - } |
|---|
| 998 | + if (rknpu_obj->sram_size > 0) |
|---|
| 999 | + return rknpu_gem_mmap_cache(rknpu_obj, vma, RKNPU_CACHE_SRAM); |
|---|
| 1000 | + else if (rknpu_obj->nbuf_size > 0) |
|---|
| 1001 | + return rknpu_gem_mmap_cache(rknpu_obj, vma, RKNPU_CACHE_NBUF); |
|---|
| 867 | 1002 | |
|---|
| 868 | 1003 | #if RKNPU_GEM_ALLOC_FROM_PAGES |
|---|
| 869 | 1004 | if ((rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS) && |
|---|
| .. | .. |
|---|
| 1045 | 1180 | } |
|---|
| 1046 | 1181 | #endif |
|---|
| 1047 | 1182 | |
|---|
| 1048 | | -static int rknpu_gem_mmap_obj(struct drm_gem_object *obj, |
|---|
| 1049 | | - struct vm_area_struct *vma) |
|---|
| 1183 | +int rknpu_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma) |
|---|
| 1050 | 1184 | { |
|---|
| 1051 | 1185 | struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); |
|---|
| 1052 | 1186 | int ret = -EINVAL; |
|---|
| .. | .. |
|---|
| 1143 | 1277 | goto err; |
|---|
| 1144 | 1278 | } |
|---|
| 1145 | 1279 | |
|---|
| 1280 | +#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE |
|---|
| 1146 | 1281 | ret = drm_prime_sg_to_page_addr_arrays(sgt, rknpu_obj->pages, NULL, |
|---|
| 1147 | 1282 | npages); |
|---|
| 1283 | +#else |
|---|
| 1284 | + ret = drm_prime_sg_to_page_array(sgt, rknpu_obj->pages, npages); |
|---|
| 1285 | +#endif |
|---|
| 1148 | 1286 | if (ret < 0) |
|---|
| 1149 | 1287 | goto err_free_large; |
|---|
| 1150 | 1288 | |
|---|
| .. | .. |
|---|
| 1172 | 1310 | return ERR_PTR(ret); |
|---|
| 1173 | 1311 | } |
|---|
| 1174 | 1312 | |
|---|
| 1313 | +#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE |
|---|
| 1175 | 1314 | void *rknpu_gem_prime_vmap(struct drm_gem_object *obj) |
|---|
| 1176 | 1315 | { |
|---|
| 1177 | 1316 | struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); |
|---|
| .. | .. |
|---|
| 1187 | 1326 | { |
|---|
| 1188 | 1327 | vunmap(vaddr); |
|---|
| 1189 | 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 |
|---|
| 1190 | 1358 | |
|---|
| 1191 | 1359 | int rknpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) |
|---|
| 1192 | 1360 | { |
|---|
| .. | .. |
|---|
| 1199 | 1367 | return rknpu_gem_mmap_obj(obj, vma); |
|---|
| 1200 | 1368 | } |
|---|
| 1201 | 1369 | |
|---|
| 1370 | +static int rknpu_cache_sync(struct rknpu_gem_object *rknpu_obj, |
|---|
| 1371 | + unsigned long *length, unsigned long *offset, |
|---|
| 1372 | + enum rknpu_cache_type cache_type) |
|---|
| 1373 | +{ |
|---|
| 1374 | +#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE |
|---|
| 1375 | + struct drm_gem_object *obj = &rknpu_obj->base; |
|---|
| 1376 | + struct rknpu_device *rknpu_dev = obj->dev->dev_private; |
|---|
| 1377 | + void __iomem *cache_base_io = NULL; |
|---|
| 1378 | + unsigned long cache_offset = 0; |
|---|
| 1379 | + unsigned long cache_size = 0; |
|---|
| 1380 | + |
|---|
| 1381 | + switch (cache_type) { |
|---|
| 1382 | + case RKNPU_CACHE_SRAM: |
|---|
| 1383 | + cache_base_io = rknpu_dev->sram_base_io; |
|---|
| 1384 | + cache_offset = rknpu_obj->sram_obj->range_start * |
|---|
| 1385 | + rknpu_dev->sram_mm->chunk_size; |
|---|
| 1386 | + cache_size = rknpu_obj->sram_size; |
|---|
| 1387 | + break; |
|---|
| 1388 | + case RKNPU_CACHE_NBUF: |
|---|
| 1389 | + cache_base_io = rknpu_dev->nbuf_base_io; |
|---|
| 1390 | + cache_offset = 0; |
|---|
| 1391 | + cache_size = rknpu_obj->nbuf_size; |
|---|
| 1392 | + break; |
|---|
| 1393 | + default: |
|---|
| 1394 | + LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); |
|---|
| 1395 | + return -EINVAL; |
|---|
| 1396 | + } |
|---|
| 1397 | + |
|---|
| 1398 | + if ((*offset + *length) <= cache_size) { |
|---|
| 1399 | + __dma_map_area(cache_base_io + *offset + cache_offset, *length, |
|---|
| 1400 | + DMA_TO_DEVICE); |
|---|
| 1401 | + __dma_unmap_area(cache_base_io + *offset + cache_offset, |
|---|
| 1402 | + *length, DMA_FROM_DEVICE); |
|---|
| 1403 | + *length = 0; |
|---|
| 1404 | + *offset = 0; |
|---|
| 1405 | + } else if (*offset >= cache_size) { |
|---|
| 1406 | + *offset -= cache_size; |
|---|
| 1407 | + } else { |
|---|
| 1408 | + unsigned long cache_length = cache_size - *offset; |
|---|
| 1409 | + |
|---|
| 1410 | + __dma_map_area(cache_base_io + *offset + cache_offset, |
|---|
| 1411 | + cache_length, DMA_TO_DEVICE); |
|---|
| 1412 | + __dma_unmap_area(cache_base_io + *offset + cache_offset, |
|---|
| 1413 | + cache_length, DMA_FROM_DEVICE); |
|---|
| 1414 | + *length -= cache_length; |
|---|
| 1415 | + *offset = 0; |
|---|
| 1416 | + } |
|---|
| 1417 | +#endif |
|---|
| 1418 | + |
|---|
| 1419 | + return 0; |
|---|
| 1420 | +} |
|---|
| 1421 | + |
|---|
| 1202 | 1422 | int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data, |
|---|
| 1203 | 1423 | struct drm_file *file_priv) |
|---|
| 1204 | 1424 | { |
|---|
| 1205 | 1425 | struct rknpu_gem_object *rknpu_obj = NULL; |
|---|
| 1426 | + struct rknpu_device *rknpu_dev = dev->dev_private; |
|---|
| 1206 | 1427 | struct rknpu_mem_sync *args = data; |
|---|
| 1207 | 1428 | struct scatterlist *sg; |
|---|
| 1429 | + dma_addr_t sg_phys_addr; |
|---|
| 1208 | 1430 | unsigned long length, offset = 0; |
|---|
| 1209 | | - unsigned long sg_left, size = 0; |
|---|
| 1431 | + unsigned long sg_offset, sg_left, size = 0; |
|---|
| 1210 | 1432 | unsigned long len = 0; |
|---|
| 1211 | 1433 | int i; |
|---|
| 1212 | 1434 | |
|---|
| .. | .. |
|---|
| 1230 | 1452 | DMA_FROM_DEVICE); |
|---|
| 1231 | 1453 | } |
|---|
| 1232 | 1454 | } else { |
|---|
| 1455 | + WARN_ON(!rknpu_dev->fake_dev); |
|---|
| 1456 | + |
|---|
| 1233 | 1457 | length = args->size; |
|---|
| 1234 | 1458 | offset = args->offset; |
|---|
| 1235 | 1459 | |
|---|
| 1236 | | - if (IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && rknpu_obj->sram_size > 0) { |
|---|
| 1237 | | - struct drm_gem_object *obj = &rknpu_obj->base; |
|---|
| 1238 | | - struct rknpu_device *rknpu_dev = obj->dev->dev_private; |
|---|
| 1239 | | - unsigned long sram_offset = |
|---|
| 1240 | | - rknpu_obj->sram_obj->range_start * |
|---|
| 1241 | | - rknpu_dev->sram_mm->chunk_size; |
|---|
| 1242 | | - if ((offset + length) <= rknpu_obj->sram_size) { |
|---|
| 1243 | | - __dma_map_area(rknpu_dev->sram_base_io + |
|---|
| 1244 | | - offset + sram_offset, |
|---|
| 1245 | | - length, DMA_TO_DEVICE); |
|---|
| 1246 | | - __dma_unmap_area(rknpu_dev->sram_base_io + |
|---|
| 1247 | | - offset + sram_offset, |
|---|
| 1248 | | - length, DMA_FROM_DEVICE); |
|---|
| 1249 | | - length = 0; |
|---|
| 1250 | | - offset = 0; |
|---|
| 1251 | | - } else if (offset >= rknpu_obj->sram_size) { |
|---|
| 1252 | | - offset -= rknpu_obj->sram_size; |
|---|
| 1253 | | - } else { |
|---|
| 1254 | | - unsigned long sram_length = |
|---|
| 1255 | | - rknpu_obj->sram_size - offset; |
|---|
| 1256 | | - __dma_map_area(rknpu_dev->sram_base_io + |
|---|
| 1257 | | - offset + sram_offset, |
|---|
| 1258 | | - sram_length, DMA_TO_DEVICE); |
|---|
| 1259 | | - __dma_unmap_area(rknpu_dev->sram_base_io + |
|---|
| 1260 | | - offset + sram_offset, |
|---|
| 1261 | | - sram_length, DMA_FROM_DEVICE); |
|---|
| 1262 | | - length -= sram_length; |
|---|
| 1263 | | - offset = 0; |
|---|
| 1264 | | - } |
|---|
| 1460 | + if (IS_ENABLED(CONFIG_NO_GKI) && |
|---|
| 1461 | + IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && |
|---|
| 1462 | + rknpu_obj->sram_size > 0) { |
|---|
| 1463 | + rknpu_cache_sync(rknpu_obj, &length, &offset, |
|---|
| 1464 | + RKNPU_CACHE_SRAM); |
|---|
| 1465 | + } else if (IS_ENABLED(CONFIG_NO_GKI) && |
|---|
| 1466 | + rknpu_obj->nbuf_size > 0) { |
|---|
| 1467 | + rknpu_cache_sync(rknpu_obj, &length, &offset, |
|---|
| 1468 | + RKNPU_CACHE_NBUF); |
|---|
| 1265 | 1469 | } |
|---|
| 1266 | 1470 | |
|---|
| 1267 | 1471 | for_each_sg(rknpu_obj->sgt->sgl, sg, rknpu_obj->sgt->nents, |
|---|
| .. | .. |
|---|
| 1273 | 1477 | if (len <= offset) |
|---|
| 1274 | 1478 | continue; |
|---|
| 1275 | 1479 | |
|---|
| 1480 | + sg_phys_addr = sg_phys(sg); |
|---|
| 1481 | + |
|---|
| 1276 | 1482 | sg_left = len - offset; |
|---|
| 1483 | + sg_offset = sg->length - sg_left; |
|---|
| 1484 | + |
|---|
| 1277 | 1485 | size = (length < sg_left) ? length : sg_left; |
|---|
| 1278 | 1486 | |
|---|
| 1279 | 1487 | if (args->flags & RKNPU_MEM_SYNC_TO_DEVICE) { |
|---|
| 1280 | | - dma_sync_sg_for_device(dev->dev, sg, 1, |
|---|
| 1281 | | - 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); |
|---|
| 1282 | 1491 | } |
|---|
| 1283 | 1492 | |
|---|
| 1284 | 1493 | if (args->flags & RKNPU_MEM_SYNC_FROM_DEVICE) { |
|---|
| 1285 | | - dma_sync_sg_for_cpu(dev->dev, sg, 1, |
|---|
| 1286 | | - 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); |
|---|
| 1287 | 1497 | } |
|---|
| 1288 | 1498 | |
|---|
| 1289 | 1499 | offset += size; |
|---|