162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/cred.h> 362306a36Sopenharmony_ci#include <linux/device.h> 462306a36Sopenharmony_ci#include <linux/dma-buf.h> 562306a36Sopenharmony_ci#include <linux/dma-resv.h> 662306a36Sopenharmony_ci#include <linux/highmem.h> 762306a36Sopenharmony_ci#include <linux/init.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/memfd.h> 1062306a36Sopenharmony_ci#include <linux/miscdevice.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/shmem_fs.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/udmabuf.h> 1562306a36Sopenharmony_ci#include <linux/vmalloc.h> 1662306a36Sopenharmony_ci#include <linux/iosys-map.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int list_limit = 1024; 1962306a36Sopenharmony_cimodule_param(list_limit, int, 0644); 2062306a36Sopenharmony_ciMODULE_PARM_DESC(list_limit, "udmabuf_create_list->count limit. Default is 1024."); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic int size_limit_mb = 64; 2362306a36Sopenharmony_cimodule_param(size_limit_mb, int, 0644); 2462306a36Sopenharmony_ciMODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is 64."); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct udmabuf { 2762306a36Sopenharmony_ci pgoff_t pagecount; 2862306a36Sopenharmony_ci struct page **pages; 2962306a36Sopenharmony_ci struct sg_table *sg; 3062306a36Sopenharmony_ci struct miscdevice *device; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 3662306a36Sopenharmony_ci struct udmabuf *ubuf = vma->vm_private_data; 3762306a36Sopenharmony_ci pgoff_t pgoff = vmf->pgoff; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (pgoff >= ubuf->pagecount) 4062306a36Sopenharmony_ci return VM_FAULT_SIGBUS; 4162306a36Sopenharmony_ci vmf->page = ubuf->pages[pgoff]; 4262306a36Sopenharmony_ci get_page(vmf->page); 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const struct vm_operations_struct udmabuf_vm_ops = { 4762306a36Sopenharmony_ci .fault = udmabuf_vm_fault, 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct udmabuf *ubuf = buf->priv; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) 5562306a36Sopenharmony_ci return -EINVAL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci vma->vm_ops = &udmabuf_vm_ops; 5862306a36Sopenharmony_ci vma->vm_private_data = ubuf; 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int vmap_udmabuf(struct dma_buf *buf, struct iosys_map *map) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct udmabuf *ubuf = buf->priv; 6562306a36Sopenharmony_ci void *vaddr; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci dma_resv_assert_held(buf->resv); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci vaddr = vm_map_ram(ubuf->pages, ubuf->pagecount, -1); 7062306a36Sopenharmony_ci if (!vaddr) 7162306a36Sopenharmony_ci return -EINVAL; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci iosys_map_set_vaddr(map, vaddr); 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void vunmap_udmabuf(struct dma_buf *buf, struct iosys_map *map) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct udmabuf *ubuf = buf->priv; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci dma_resv_assert_held(buf->resv); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci vm_unmap_ram(map->vaddr, ubuf->pagecount); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf, 8762306a36Sopenharmony_ci enum dma_data_direction direction) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct udmabuf *ubuf = buf->priv; 9062306a36Sopenharmony_ci struct sg_table *sg; 9162306a36Sopenharmony_ci int ret; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci sg = kzalloc(sizeof(*sg), GFP_KERNEL); 9462306a36Sopenharmony_ci if (!sg) 9562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 9662306a36Sopenharmony_ci ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, 9762306a36Sopenharmony_ci 0, ubuf->pagecount << PAGE_SHIFT, 9862306a36Sopenharmony_ci GFP_KERNEL); 9962306a36Sopenharmony_ci if (ret < 0) 10062306a36Sopenharmony_ci goto err; 10162306a36Sopenharmony_ci ret = dma_map_sgtable(dev, sg, direction, 0); 10262306a36Sopenharmony_ci if (ret < 0) 10362306a36Sopenharmony_ci goto err; 10462306a36Sopenharmony_ci return sg; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cierr: 10762306a36Sopenharmony_ci sg_free_table(sg); 10862306a36Sopenharmony_ci kfree(sg); 10962306a36Sopenharmony_ci return ERR_PTR(ret); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void put_sg_table(struct device *dev, struct sg_table *sg, 11362306a36Sopenharmony_ci enum dma_data_direction direction) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci dma_unmap_sgtable(dev, sg, direction, 0); 11662306a36Sopenharmony_ci sg_free_table(sg); 11762306a36Sopenharmony_ci kfree(sg); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct sg_table *map_udmabuf(struct dma_buf_attachment *at, 12162306a36Sopenharmony_ci enum dma_data_direction direction) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci return get_sg_table(at->dev, at->dmabuf, direction); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void unmap_udmabuf(struct dma_buf_attachment *at, 12762306a36Sopenharmony_ci struct sg_table *sg, 12862306a36Sopenharmony_ci enum dma_data_direction direction) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return put_sg_table(at->dev, sg, direction); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void release_udmabuf(struct dma_buf *buf) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct udmabuf *ubuf = buf->priv; 13662306a36Sopenharmony_ci struct device *dev = ubuf->device->this_device; 13762306a36Sopenharmony_ci pgoff_t pg; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (ubuf->sg) 14062306a36Sopenharmony_ci put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci for (pg = 0; pg < ubuf->pagecount; pg++) 14362306a36Sopenharmony_ci put_page(ubuf->pages[pg]); 14462306a36Sopenharmony_ci kfree(ubuf->pages); 14562306a36Sopenharmony_ci kfree(ubuf); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int begin_cpu_udmabuf(struct dma_buf *buf, 14962306a36Sopenharmony_ci enum dma_data_direction direction) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct udmabuf *ubuf = buf->priv; 15262306a36Sopenharmony_ci struct device *dev = ubuf->device->this_device; 15362306a36Sopenharmony_ci int ret = 0; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (!ubuf->sg) { 15662306a36Sopenharmony_ci ubuf->sg = get_sg_table(dev, buf, direction); 15762306a36Sopenharmony_ci if (IS_ERR(ubuf->sg)) { 15862306a36Sopenharmony_ci ret = PTR_ERR(ubuf->sg); 15962306a36Sopenharmony_ci ubuf->sg = NULL; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents, 16362306a36Sopenharmony_ci direction); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return ret; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int end_cpu_udmabuf(struct dma_buf *buf, 17062306a36Sopenharmony_ci enum dma_data_direction direction) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct udmabuf *ubuf = buf->priv; 17362306a36Sopenharmony_ci struct device *dev = ubuf->device->this_device; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!ubuf->sg) 17662306a36Sopenharmony_ci return -EINVAL; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci dma_sync_sg_for_device(dev, ubuf->sg->sgl, ubuf->sg->nents, direction); 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const struct dma_buf_ops udmabuf_ops = { 18362306a36Sopenharmony_ci .cache_sgt_mapping = true, 18462306a36Sopenharmony_ci .map_dma_buf = map_udmabuf, 18562306a36Sopenharmony_ci .unmap_dma_buf = unmap_udmabuf, 18662306a36Sopenharmony_ci .release = release_udmabuf, 18762306a36Sopenharmony_ci .mmap = mmap_udmabuf, 18862306a36Sopenharmony_ci .vmap = vmap_udmabuf, 18962306a36Sopenharmony_ci .vunmap = vunmap_udmabuf, 19062306a36Sopenharmony_ci .begin_cpu_access = begin_cpu_udmabuf, 19162306a36Sopenharmony_ci .end_cpu_access = end_cpu_udmabuf, 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#define SEALS_WANTED (F_SEAL_SHRINK) 19562306a36Sopenharmony_ci#define SEALS_DENIED (F_SEAL_WRITE) 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic long udmabuf_create(struct miscdevice *device, 19862306a36Sopenharmony_ci struct udmabuf_create_list *head, 19962306a36Sopenharmony_ci struct udmabuf_create_item *list) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 20262306a36Sopenharmony_ci struct file *memfd = NULL; 20362306a36Sopenharmony_ci struct address_space *mapping = NULL; 20462306a36Sopenharmony_ci struct udmabuf *ubuf; 20562306a36Sopenharmony_ci struct dma_buf *buf; 20662306a36Sopenharmony_ci pgoff_t pgoff, pgcnt, pgidx, pgbuf = 0, pglimit; 20762306a36Sopenharmony_ci struct page *page; 20862306a36Sopenharmony_ci int seals, ret = -EINVAL; 20962306a36Sopenharmony_ci u32 i, flags; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); 21262306a36Sopenharmony_ci if (!ubuf) 21362306a36Sopenharmony_ci return -ENOMEM; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; 21662306a36Sopenharmony_ci for (i = 0; i < head->count; i++) { 21762306a36Sopenharmony_ci if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) 21862306a36Sopenharmony_ci goto err; 21962306a36Sopenharmony_ci if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) 22062306a36Sopenharmony_ci goto err; 22162306a36Sopenharmony_ci ubuf->pagecount += list[i].size >> PAGE_SHIFT; 22262306a36Sopenharmony_ci if (ubuf->pagecount > pglimit) 22362306a36Sopenharmony_ci goto err; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (!ubuf->pagecount) 22762306a36Sopenharmony_ci goto err; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), 23062306a36Sopenharmony_ci GFP_KERNEL); 23162306a36Sopenharmony_ci if (!ubuf->pages) { 23262306a36Sopenharmony_ci ret = -ENOMEM; 23362306a36Sopenharmony_ci goto err; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci pgbuf = 0; 23762306a36Sopenharmony_ci for (i = 0; i < head->count; i++) { 23862306a36Sopenharmony_ci ret = -EBADFD; 23962306a36Sopenharmony_ci memfd = fget(list[i].memfd); 24062306a36Sopenharmony_ci if (!memfd) 24162306a36Sopenharmony_ci goto err; 24262306a36Sopenharmony_ci mapping = memfd->f_mapping; 24362306a36Sopenharmony_ci if (!shmem_mapping(mapping)) 24462306a36Sopenharmony_ci goto err; 24562306a36Sopenharmony_ci seals = memfd_fcntl(memfd, F_GET_SEALS, 0); 24662306a36Sopenharmony_ci if (seals == -EINVAL) 24762306a36Sopenharmony_ci goto err; 24862306a36Sopenharmony_ci ret = -EINVAL; 24962306a36Sopenharmony_ci if ((seals & SEALS_WANTED) != SEALS_WANTED || 25062306a36Sopenharmony_ci (seals & SEALS_DENIED) != 0) 25162306a36Sopenharmony_ci goto err; 25262306a36Sopenharmony_ci pgoff = list[i].offset >> PAGE_SHIFT; 25362306a36Sopenharmony_ci pgcnt = list[i].size >> PAGE_SHIFT; 25462306a36Sopenharmony_ci for (pgidx = 0; pgidx < pgcnt; pgidx++) { 25562306a36Sopenharmony_ci page = shmem_read_mapping_page(mapping, pgoff + pgidx); 25662306a36Sopenharmony_ci if (IS_ERR(page)) { 25762306a36Sopenharmony_ci ret = PTR_ERR(page); 25862306a36Sopenharmony_ci goto err; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci ubuf->pages[pgbuf++] = page; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci fput(memfd); 26362306a36Sopenharmony_ci memfd = NULL; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci exp_info.ops = &udmabuf_ops; 26762306a36Sopenharmony_ci exp_info.size = ubuf->pagecount << PAGE_SHIFT; 26862306a36Sopenharmony_ci exp_info.priv = ubuf; 26962306a36Sopenharmony_ci exp_info.flags = O_RDWR; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ubuf->device = device; 27262306a36Sopenharmony_ci buf = dma_buf_export(&exp_info); 27362306a36Sopenharmony_ci if (IS_ERR(buf)) { 27462306a36Sopenharmony_ci ret = PTR_ERR(buf); 27562306a36Sopenharmony_ci goto err; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci flags = 0; 27962306a36Sopenharmony_ci if (head->flags & UDMABUF_FLAGS_CLOEXEC) 28062306a36Sopenharmony_ci flags |= O_CLOEXEC; 28162306a36Sopenharmony_ci return dma_buf_fd(buf, flags); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cierr: 28462306a36Sopenharmony_ci while (pgbuf > 0) 28562306a36Sopenharmony_ci put_page(ubuf->pages[--pgbuf]); 28662306a36Sopenharmony_ci if (memfd) 28762306a36Sopenharmony_ci fput(memfd); 28862306a36Sopenharmony_ci kfree(ubuf->pages); 28962306a36Sopenharmony_ci kfree(ubuf); 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic long udmabuf_ioctl_create(struct file *filp, unsigned long arg) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct udmabuf_create create; 29662306a36Sopenharmony_ci struct udmabuf_create_list head; 29762306a36Sopenharmony_ci struct udmabuf_create_item list; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (copy_from_user(&create, (void __user *)arg, 30062306a36Sopenharmony_ci sizeof(create))) 30162306a36Sopenharmony_ci return -EFAULT; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci head.flags = create.flags; 30462306a36Sopenharmony_ci head.count = 1; 30562306a36Sopenharmony_ci list.memfd = create.memfd; 30662306a36Sopenharmony_ci list.offset = create.offset; 30762306a36Sopenharmony_ci list.size = create.size; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return udmabuf_create(filp->private_data, &head, &list); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct udmabuf_create_list head; 31562306a36Sopenharmony_ci struct udmabuf_create_item *list; 31662306a36Sopenharmony_ci int ret = -EINVAL; 31762306a36Sopenharmony_ci u32 lsize; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (copy_from_user(&head, (void __user *)arg, sizeof(head))) 32062306a36Sopenharmony_ci return -EFAULT; 32162306a36Sopenharmony_ci if (head.count > list_limit) 32262306a36Sopenharmony_ci return -EINVAL; 32362306a36Sopenharmony_ci lsize = sizeof(struct udmabuf_create_item) * head.count; 32462306a36Sopenharmony_ci list = memdup_user((void __user *)(arg + sizeof(head)), lsize); 32562306a36Sopenharmony_ci if (IS_ERR(list)) 32662306a36Sopenharmony_ci return PTR_ERR(list); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ret = udmabuf_create(filp->private_data, &head, list); 32962306a36Sopenharmony_ci kfree(list); 33062306a36Sopenharmony_ci return ret; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic long udmabuf_ioctl(struct file *filp, unsigned int ioctl, 33462306a36Sopenharmony_ci unsigned long arg) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci long ret; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci switch (ioctl) { 33962306a36Sopenharmony_ci case UDMABUF_CREATE: 34062306a36Sopenharmony_ci ret = udmabuf_ioctl_create(filp, arg); 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci case UDMABUF_CREATE_LIST: 34362306a36Sopenharmony_ci ret = udmabuf_ioctl_create_list(filp, arg); 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci default: 34662306a36Sopenharmony_ci ret = -ENOTTY; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic const struct file_operations udmabuf_fops = { 35362306a36Sopenharmony_ci .owner = THIS_MODULE, 35462306a36Sopenharmony_ci .unlocked_ioctl = udmabuf_ioctl, 35562306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 35662306a36Sopenharmony_ci .compat_ioctl = udmabuf_ioctl, 35762306a36Sopenharmony_ci#endif 35862306a36Sopenharmony_ci}; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic struct miscdevice udmabuf_misc = { 36162306a36Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 36262306a36Sopenharmony_ci .name = "udmabuf", 36362306a36Sopenharmony_ci .fops = &udmabuf_fops, 36462306a36Sopenharmony_ci}; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int __init udmabuf_dev_init(void) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci int ret; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci ret = misc_register(&udmabuf_misc); 37162306a36Sopenharmony_ci if (ret < 0) { 37262306a36Sopenharmony_ci pr_err("Could not initialize udmabuf device\n"); 37362306a36Sopenharmony_ci return ret; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ret = dma_coerce_mask_and_coherent(udmabuf_misc.this_device, 37762306a36Sopenharmony_ci DMA_BIT_MASK(64)); 37862306a36Sopenharmony_ci if (ret < 0) { 37962306a36Sopenharmony_ci pr_err("Could not setup DMA mask for udmabuf device\n"); 38062306a36Sopenharmony_ci misc_deregister(&udmabuf_misc); 38162306a36Sopenharmony_ci return ret; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void __exit udmabuf_dev_exit(void) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci misc_deregister(&udmabuf_misc); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cimodule_init(udmabuf_dev_init) 39362306a36Sopenharmony_cimodule_exit(udmabuf_dev_exit) 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ciMODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); 396