| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * |
|---|
| 4 | | - * (C) COPYRIGHT 2012-2021 ARM Limited. All rights reserved. |
|---|
| 4 | + * (C) COPYRIGHT 2012-2022 ARM Limited. All rights reserved. |
|---|
| 5 | 5 | * |
|---|
| 6 | 6 | * This program is free software and is provided to you under the terms of the |
|---|
| 7 | 7 | * GNU General Public License version 2 as published by the Free Software |
|---|
| .. | .. |
|---|
| 19 | 19 | * |
|---|
| 20 | 20 | */ |
|---|
| 21 | 21 | |
|---|
| 22 | | -#include <linux/dma-buf-test-exporter.h> |
|---|
| 22 | +#include <uapi/base/arm/dma_buf_test_exporter/dma-buf-test-exporter.h> |
|---|
| 23 | 23 | #include <linux/dma-buf.h> |
|---|
| 24 | 24 | #include <linux/miscdevice.h> |
|---|
| 25 | 25 | #include <linux/slab.h> |
|---|
| .. | .. |
|---|
| 30 | 30 | #include <linux/atomic.h> |
|---|
| 31 | 31 | #include <linux/mm.h> |
|---|
| 32 | 32 | #include <linux/highmem.h> |
|---|
| 33 | | -#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE) |
|---|
| 34 | | -#include <linux/dma-attrs.h> |
|---|
| 35 | | -#endif |
|---|
| 36 | 33 | #include <linux/dma-mapping.h> |
|---|
| 34 | + |
|---|
| 35 | +#define DMA_BUF_TE_VER_MAJOR 1 |
|---|
| 36 | +#define DMA_BUF_TE_VER_MINOR 0 |
|---|
| 37 | 37 | |
|---|
| 38 | 38 | /* Maximum size allowed in a single DMA_BUF_TE_ALLOC call */ |
|---|
| 39 | 39 | #define DMA_BUF_TE_ALLOC_MAX_SIZE ((8ull << 30) >> PAGE_SHIFT) /* 8 GB */ |
|---|
| .. | .. |
|---|
| 81 | 81 | #endif |
|---|
| 82 | 82 | { |
|---|
| 83 | 83 | struct dma_buf_te_alloc *alloc; |
|---|
| 84 | + |
|---|
| 84 | 85 | alloc = buf->priv; |
|---|
| 85 | 86 | |
|---|
| 86 | 87 | if (alloc->fail_attach) |
|---|
| .. | .. |
|---|
| 95 | 96 | return 0; |
|---|
| 96 | 97 | } |
|---|
| 97 | 98 | |
|---|
| 99 | +/** |
|---|
| 100 | + * dma_buf_te_detach - The detach callback function to release &attachment |
|---|
| 101 | + * |
|---|
| 102 | + * @buf: buffer for the &attachment |
|---|
| 103 | + * @attachment: attachment data to be released |
|---|
| 104 | + */ |
|---|
| 98 | 105 | static void dma_buf_te_detach(struct dma_buf *buf, struct dma_buf_attachment *attachment) |
|---|
| 99 | 106 | { |
|---|
| 100 | 107 | struct dma_buf_te_alloc *alloc = buf->priv; |
|---|
| .. | .. |
|---|
| 199 | 206 | { |
|---|
| 200 | 207 | size_t i; |
|---|
| 201 | 208 | struct dma_buf_te_alloc *alloc; |
|---|
| 209 | + |
|---|
| 202 | 210 | alloc = buf->priv; |
|---|
| 203 | 211 | /* no need for locking */ |
|---|
| 204 | 212 | |
|---|
| 205 | 213 | if (alloc->contiguous) { |
|---|
| 206 | | -#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE) |
|---|
| 207 | 214 | dma_free_attrs(te_device.this_device, |
|---|
| 208 | 215 | alloc->nr_pages * PAGE_SIZE, |
|---|
| 209 | 216 | alloc->contig_cpu_addr, |
|---|
| 210 | 217 | alloc->contig_dma_addr, |
|---|
| 211 | 218 | DMA_ATTR_WRITE_COMBINE); |
|---|
| 212 | | -#else |
|---|
| 213 | | - DEFINE_DMA_ATTRS(attrs); |
|---|
| 214 | | - |
|---|
| 215 | | - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); |
|---|
| 216 | | - dma_free_attrs(te_device.this_device, |
|---|
| 217 | | - alloc->nr_pages * PAGE_SIZE, |
|---|
| 218 | | - alloc->contig_cpu_addr, alloc->contig_dma_addr, &attrs); |
|---|
| 219 | | -#endif |
|---|
| 220 | 219 | } else { |
|---|
| 221 | 220 | for (i = 0; i < alloc->nr_pages; i++) |
|---|
| 222 | 221 | __free_page(alloc->pages[i]); |
|---|
| .. | .. |
|---|
| 240 | 239 | list_for_each_entry(attachment, &dmabuf->attachments, node) { |
|---|
| 241 | 240 | struct dma_buf_te_attachment *pa = attachment->priv; |
|---|
| 242 | 241 | struct sg_table *sg = pa->sg; |
|---|
| 242 | + |
|---|
| 243 | 243 | if (!sg) { |
|---|
| 244 | 244 | dev_dbg(te_device.this_device, "no mapping for device %s\n", dev_name(attachment->dev)); |
|---|
| 245 | 245 | continue; |
|---|
| .. | .. |
|---|
| 260 | 260 | return 0; |
|---|
| 261 | 261 | } |
|---|
| 262 | 262 | |
|---|
| 263 | | -#if (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) |
|---|
| 264 | 263 | static int dma_buf_te_begin_cpu_access(struct dma_buf *dmabuf, |
|---|
| 265 | 264 | enum dma_data_direction direction) |
|---|
| 266 | | -#else |
|---|
| 267 | | -static int dma_buf_te_begin_cpu_access(struct dma_buf *dmabuf, size_t start, |
|---|
| 268 | | - size_t len, |
|---|
| 269 | | - enum dma_data_direction direction) |
|---|
| 270 | | -#endif |
|---|
| 271 | 265 | { |
|---|
| 272 | 266 | return dma_buf_te_sync(dmabuf, direction, true); |
|---|
| 273 | 267 | } |
|---|
| 274 | 268 | |
|---|
| 275 | | -#if (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) |
|---|
| 276 | 269 | static int dma_buf_te_end_cpu_access(struct dma_buf *dmabuf, |
|---|
| 277 | 270 | enum dma_data_direction direction) |
|---|
| 278 | 271 | { |
|---|
| 279 | 272 | return dma_buf_te_sync(dmabuf, direction, false); |
|---|
| 280 | 273 | } |
|---|
| 281 | | -#else |
|---|
| 282 | | -static void dma_buf_te_end_cpu_access(struct dma_buf *dmabuf, size_t start, |
|---|
| 283 | | - size_t len, |
|---|
| 284 | | - enum dma_data_direction direction) |
|---|
| 285 | | -{ |
|---|
| 286 | | - dma_buf_te_sync(dmabuf, direction, false); |
|---|
| 287 | | -} |
|---|
| 288 | | -#endif |
|---|
| 289 | 274 | |
|---|
| 290 | 275 | static void dma_buf_te_mmap_open(struct vm_area_struct *vma) |
|---|
| 291 | 276 | { |
|---|
| 292 | 277 | struct dma_buf *dma_buf; |
|---|
| 293 | 278 | struct dma_buf_te_alloc *alloc; |
|---|
| 279 | + |
|---|
| 294 | 280 | dma_buf = vma->vm_private_data; |
|---|
| 295 | 281 | alloc = dma_buf->priv; |
|---|
| 296 | 282 | |
|---|
| .. | .. |
|---|
| 303 | 289 | { |
|---|
| 304 | 290 | struct dma_buf *dma_buf; |
|---|
| 305 | 291 | struct dma_buf_te_alloc *alloc; |
|---|
| 292 | + |
|---|
| 306 | 293 | dma_buf = vma->vm_private_data; |
|---|
| 307 | 294 | alloc = dma_buf->priv; |
|---|
| 308 | 295 | |
|---|
| .. | .. |
|---|
| 344 | 331 | return 0; |
|---|
| 345 | 332 | } |
|---|
| 346 | 333 | |
|---|
| 347 | | -struct vm_operations_struct dma_buf_te_vm_ops = { |
|---|
| 334 | +static const struct vm_operations_struct dma_buf_te_vm_ops = { |
|---|
| 348 | 335 | .open = dma_buf_te_mmap_open, |
|---|
| 349 | 336 | .close = dma_buf_te_mmap_close, |
|---|
| 350 | 337 | .fault = dma_buf_te_mmap_fault |
|---|
| .. | .. |
|---|
| 353 | 340 | static int dma_buf_te_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) |
|---|
| 354 | 341 | { |
|---|
| 355 | 342 | struct dma_buf_te_alloc *alloc; |
|---|
| 343 | + |
|---|
| 356 | 344 | alloc = dmabuf->priv; |
|---|
| 357 | 345 | |
|---|
| 358 | 346 | if (alloc->fail_mmap) |
|---|
| .. | .. |
|---|
| 398 | 386 | return; |
|---|
| 399 | 387 | |
|---|
| 400 | 388 | kunmap(alloc->pages[page_num]); |
|---|
| 401 | | - return; |
|---|
| 402 | 389 | } |
|---|
| 403 | 390 | |
|---|
| 404 | 391 | static struct dma_buf_ops dma_buf_te_ops = { |
|---|
| .. | .. |
|---|
| 510 | 497 | if (contiguous) { |
|---|
| 511 | 498 | dma_addr_t dma_aux; |
|---|
| 512 | 499 | |
|---|
| 513 | | -#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE) |
|---|
| 514 | 500 | alloc->contig_cpu_addr = dma_alloc_attrs(te_device.this_device, |
|---|
| 515 | 501 | alloc->nr_pages * PAGE_SIZE, |
|---|
| 516 | 502 | &alloc->contig_dma_addr, |
|---|
| 517 | 503 | GFP_KERNEL | __GFP_ZERO, |
|---|
| 518 | 504 | DMA_ATTR_WRITE_COMBINE); |
|---|
| 519 | | -#else |
|---|
| 520 | | - DEFINE_DMA_ATTRS(attrs); |
|---|
| 521 | | - |
|---|
| 522 | | - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); |
|---|
| 523 | | - alloc->contig_cpu_addr = dma_alloc_attrs(te_device.this_device, |
|---|
| 524 | | - alloc->nr_pages * PAGE_SIZE, |
|---|
| 525 | | - &alloc->contig_dma_addr, |
|---|
| 526 | | - GFP_KERNEL | __GFP_ZERO, &attrs); |
|---|
| 527 | | -#endif |
|---|
| 528 | 505 | if (!alloc->contig_cpu_addr) { |
|---|
| 529 | 506 | dev_err(te_device.this_device, "%s: couldn't alloc contiguous buffer %zu pages", |
|---|
| 530 | 507 | __func__, alloc->nr_pages); |
|---|
| .. | .. |
|---|
| 580 | 557 | /* i still valid */ |
|---|
| 581 | 558 | no_page: |
|---|
| 582 | 559 | if (contiguous) { |
|---|
| 583 | | -#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE) |
|---|
| 584 | 560 | dma_free_attrs(te_device.this_device, |
|---|
| 585 | 561 | alloc->nr_pages * PAGE_SIZE, |
|---|
| 586 | 562 | alloc->contig_cpu_addr, |
|---|
| 587 | 563 | alloc->contig_dma_addr, |
|---|
| 588 | 564 | DMA_ATTR_WRITE_COMBINE); |
|---|
| 589 | | -#else |
|---|
| 590 | | - DEFINE_DMA_ATTRS(attrs); |
|---|
| 591 | | - |
|---|
| 592 | | - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); |
|---|
| 593 | | - dma_free_attrs(te_device.this_device, |
|---|
| 594 | | - alloc->nr_pages * PAGE_SIZE, |
|---|
| 595 | | - alloc->contig_cpu_addr, alloc->contig_dma_addr, &attrs); |
|---|
| 596 | | -#endif |
|---|
| 597 | 565 | } else { |
|---|
| 598 | 566 | while (i-- > 0) |
|---|
| 599 | 567 | __free_page(alloc->pages[i]); |
|---|
| .. | .. |
|---|
| 692 | 660 | struct sg_table *sgt; |
|---|
| 693 | 661 | struct scatterlist *sg; |
|---|
| 694 | 662 | unsigned int count; |
|---|
| 695 | | - unsigned int offset = 0; |
|---|
| 696 | 663 | int ret = 0; |
|---|
| 697 | 664 | size_t i; |
|---|
| 698 | 665 | |
|---|
| .. | .. |
|---|
| 706 | 673 | goto no_import; |
|---|
| 707 | 674 | } |
|---|
| 708 | 675 | |
|---|
| 709 | | - ret = dma_buf_begin_cpu_access(dma_buf, |
|---|
| 710 | | -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE |
|---|
| 711 | | - 0, dma_buf->size, |
|---|
| 712 | | -#endif |
|---|
| 713 | | - DMA_BIDIRECTIONAL); |
|---|
| 676 | + ret = dma_buf_begin_cpu_access(dma_buf, DMA_BIDIRECTIONAL); |
|---|
| 714 | 677 | if (ret) |
|---|
| 715 | 678 | goto no_cpu_access; |
|---|
| 716 | 679 | |
|---|
| .. | .. |
|---|
| 733 | 696 | dma_buf_kunmap(dma_buf, i >> PAGE_SHIFT, addr); |
|---|
| 734 | 697 | #endif |
|---|
| 735 | 698 | } |
|---|
| 736 | | - offset += sg_dma_len(sg); |
|---|
| 737 | 699 | } |
|---|
| 738 | 700 | |
|---|
| 739 | 701 | no_kmap: |
|---|
| 740 | | - dma_buf_end_cpu_access(dma_buf, |
|---|
| 741 | | -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE |
|---|
| 742 | | - 0, dma_buf->size, |
|---|
| 743 | | -#endif |
|---|
| 744 | | - DMA_BIDIRECTIONAL); |
|---|
| 702 | + dma_buf_end_cpu_access(dma_buf, DMA_BIDIRECTIONAL); |
|---|
| 745 | 703 | no_cpu_access: |
|---|
| 746 | 704 | dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL); |
|---|
| 747 | 705 | no_import: |
|---|
| .. | .. |
|---|
| 798 | 756 | static int __init dma_buf_te_init(void) |
|---|
| 799 | 757 | { |
|---|
| 800 | 758 | int res; |
|---|
| 759 | + |
|---|
| 801 | 760 | te_device.minor = MISC_DYNAMIC_MINOR; |
|---|
| 802 | 761 | te_device.name = "dma_buf_te"; |
|---|
| 803 | 762 | te_device.fops = &dma_buf_te_fops; |
|---|
| 804 | 763 | |
|---|
| 805 | 764 | res = misc_register(&te_device); |
|---|
| 806 | 765 | if (res) { |
|---|
| 807 | | - printk(KERN_WARNING"Misc device registration failed of 'dma_buf_te'\n"); |
|---|
| 766 | + pr_warn("Misc device registration failed of 'dma_buf_te'\n"); |
|---|
| 808 | 767 | return res; |
|---|
| 809 | 768 | } |
|---|
| 810 | 769 | te_device.this_device->coherent_dma_mask = DMA_BIT_MASK(32); |
|---|
| .. | .. |
|---|
| 822 | 781 | module_init(dma_buf_te_init); |
|---|
| 823 | 782 | module_exit(dma_buf_te_exit); |
|---|
| 824 | 783 | MODULE_LICENSE("GPL"); |
|---|
| 784 | +MODULE_INFO(import_ns, "DMA_BUF"); |
|---|