2 * Copyright (C) 2013 Google, Inc.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <linux/dma-buf.h>
16 #include <linux/highmem.h>
17 #include <linux/memblock.h>
18 #include <linux/slab.h>
20 struct adf_memblock_pdata {
24 static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach,
25 enum dma_data_direction direction)
27 struct adf_memblock_pdata *pdata = attach->dmabuf->priv;
28 unsigned long pfn = PFN_DOWN(pdata->base);
29 struct page *page = pfn_to_page(pfn);
30 struct sg_table *table;
33 table = kzalloc(sizeof(*table), GFP_KERNEL);
35 return ERR_PTR(-ENOMEM);
37 ret = sg_alloc_table(table, 1, GFP_KERNEL);
41 sg_set_page(table->sgl, page, attach->dmabuf->size, 0);
43 nents = dma_map_sg(attach->dev, table->sgl, 1, direction);
58 static void adf_memblock_unmap(struct dma_buf_attachment *attach,
59 struct sg_table *table, enum dma_data_direction direction)
61 dma_unmap_sg(attach->dev, table->sgl, 1, direction);
65 static void __init_memblock adf_memblock_release(struct dma_buf *buf)
67 struct adf_memblock_pdata *pdata = buf->priv;
68 int err = memblock_free(pdata->base, buf->size);
71 pr_warn("%s: freeing memblock failed: %d\n", __func__, err);
75 static void *adf_memblock_do_kmap(struct dma_buf *buf, unsigned long pgoffset,
78 struct adf_memblock_pdata *pdata = buf->priv;
79 unsigned long pfn = PFN_DOWN(pdata->base) + pgoffset;
80 struct page *page = pfn_to_page(pfn);
83 return kmap_atomic(page);
88 static void *adf_memblock_kmap_atomic(struct dma_buf *buf,
89 unsigned long pgoffset)
91 return adf_memblock_do_kmap(buf, pgoffset, true);
94 static void adf_memblock_kunmap_atomic(struct dma_buf *buf,
95 unsigned long pgoffset, void *vaddr)
100 static void *adf_memblock_kmap(struct dma_buf *buf, unsigned long pgoffset)
102 return adf_memblock_do_kmap(buf, pgoffset, false);
105 static void adf_memblock_kunmap(struct dma_buf *buf, unsigned long pgoffset,
111 static int adf_memblock_mmap(struct dma_buf *buf, struct vm_area_struct *vma)
113 struct adf_memblock_pdata *pdata = buf->priv;
115 return remap_pfn_range(vma, vma->vm_start, PFN_DOWN(pdata->base),
116 vma->vm_end - vma->vm_start, vma->vm_page_prot);
119 struct dma_buf_ops adf_memblock_ops = {
120 .map_dma_buf = adf_memblock_map,
121 .unmap_dma_buf = adf_memblock_unmap,
122 .release = adf_memblock_release,
123 .kmap_atomic = adf_memblock_kmap_atomic,
124 .kunmap_atomic = adf_memblock_kunmap_atomic,
125 .kmap = adf_memblock_kmap,
126 .kunmap = adf_memblock_kunmap,
127 .mmap = adf_memblock_mmap,
131 * adf_memblock_export - export a memblock reserved area as a dma-buf
133 * @base: base physical address
134 * @size: memblock size
135 * @flags: mode flags for the dma-buf's file
137 * @base and @size must be page-aligned.
139 * Returns a dma-buf on success or ERR_PTR(-errno) on failure.
141 struct dma_buf *adf_memblock_export(phys_addr_t base, size_t size, int flags)
143 struct adf_memblock_pdata *pdata;
145 DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
147 if (PAGE_ALIGN(base) != base || PAGE_ALIGN(size) != size)
148 return ERR_PTR(-EINVAL);
150 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
152 return ERR_PTR(-ENOMEM);
155 exp_info.ops = &adf_memblock_ops;
156 exp_info.size = size;
157 exp_info.flags = flags;
158 exp_info.priv = pdata;
160 buf = dma_buf_export(&exp_info);
166 EXPORT_SYMBOL(adf_memblock_export);