summaryrefslogtreecommitdiff
path: root/drivers/media/video/tiler
diff options
context:
space:
mode:
authorLajos Molnar <molnar@ti.com>2011-04-07 08:41:17 +0100
committerAndy Green <andy.green@linaro.org>2011-04-07 08:41:17 +0100
commit62638d129f1aa1652ceb269309cd857f83f7d0f1 (patch)
treea12bedc1b8ece676f0d6a2abd79407d5f86bdc49 /drivers/media/video/tiler
parent9661452b373503016263556a36f9416ac63b91a3 (diff)
TILER: Added support for partial mmaping of TILER buffers
Added support for mmapping only a portion of a TILER buffer. Also added helper functions that can be used by other drivers that use TILER to mmap and ioremap portions of TILER blocks. Signed-off-by: Lajos Molnar <molnar@ti.com>
Diffstat (limited to 'drivers/media/video/tiler')
-rw-r--r--drivers/media/video/tiler/tiler.c110
1 files changed, 95 insertions, 15 deletions
diff --git a/drivers/media/video/tiler/tiler.c b/drivers/media/video/tiler/tiler.c
index bbfebeeca2e..903df67b86f 100644
--- a/drivers/media/video/tiler/tiler.c
+++ b/drivers/media/video/tiler/tiler.c
@@ -871,20 +871,98 @@ static struct mem_info *__get_area(enum tiler_fmt fmt, u32 width, u32 height,
return mi;
}
+s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
+ struct vm_area_struct *vma, u32 voffs)
+{
+ u32 v, p;
+ u32 len; /* area to map */
+
+ /* don't allow mremap */
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+
+ /* mapping must fit into vma */
+ if (vma->vm_start > vma->vm_start + voffs ||
+ vma->vm_start + voffs > vma->vm_start + voffs + size ||
+ vma->vm_start + voffs + size > vma->vm_end)
+ BUG();
+
+ /* mapping must fit into block */
+ if (offs > offs + size ||
+ offs + size > tiler_size(blk))
+ BUG();
+
+ v = tiler_vstride(blk);
+ p = tiler_pstride(blk);
+
+ /* remap block portion */
+ len = v - (offs % v); /* initial area to map */
+ while (size) {
+ if (len > size)
+ len = size;
+
+ vma->vm_pgoff = (blk->phys + offs) >> PAGE_SHIFT;
+ if (remap_pfn_range(vma, vma->vm_start + voffs, vma->vm_pgoff,
+ len, vma->vm_page_prot))
+ return -EAGAIN;
+ voffs += len;
+ offs += len + p - v;
+ size -= len;
+ len = v; /* subsequent area to map */
+ }
+ return 0;
+}
+EXPORT_SYMBOL(tiler_mmap_blk);
+
+s32 tiler_ioremap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
+ u32 addr, u32 mtype)
+{
+ u32 v, p;
+ u32 len; /* area to map */
+ const struct mem_type *type = get_mem_type(mtype);
+
+ /* mapping must fit into address space */
+ if (addr > addr + size)
+ BUG();
+
+ /* mapping must fit into block */
+ if (offs > offs + size ||
+ offs + size > tiler_size(blk))
+ BUG();
+
+ v = tiler_vstride(blk);
+ p = tiler_pstride(blk);
+
+ /* move offset and address to end */
+ offs += blk->phys + size;
+ addr += size;
+
+ len = v - (offs % v); /* initial area to map */
+ while (size) {
+ while (len && size) {
+ if (ioremap_page(addr - size, offs - size, type))
+ return -EAGAIN;
+ len -= PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ offs += p - v;
+ len = v; /* subsequent area to map */
+ }
+ return 0;
+}
+EXPORT_SYMBOL(tiler_ioremap_blk);
+
static s32 tiler_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct __buf_info *_b = NULL;
struct tiler_buf_info *b = NULL;
- s32 i = 0, j = 0, k = 0, m = 0, p = 0;
+ u32 i, map_offs, map_size, blk_offs, blk_size, mapped_size;
struct process_info *pi = filp->private_data;
u32 offs = vma->vm_pgoff << PAGE_SHIFT;
u32 size = vma->vm_end - vma->vm_start;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- /* don't allow mremap */
- vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
-
mutex_lock(&mtx);
list_for_each_entry(_b, &pi->bufs, by_pid) {
if (offs >= _b->buf_info.offset &&
@@ -897,17 +975,19 @@ static s32 tiler_mmap(struct file *filp, struct vm_area_struct *vma)
if (!b)
return -ENXIO;
- for (i = 0; i < b->num_blocks; i++) {
- p = tiler_vstride(&_b->mi[i]->blk);
- for (m = j = 0; j < _b->mi[i]->blk.height; j++) {
- /* map each page of the line */
- vma->vm_pgoff = (b->blocks[i].ssptr + m) >> PAGE_SHIFT;
- if (remap_pfn_range(vma, vma->vm_start + k,
- vma->vm_pgoff, p, vma->vm_page_prot))
- return -EAGAIN;
- k += p;
- m += tiler_pstride(&_b->mi[i]->blk);
- }
+ /* mmap relevant blocks */
+ blk_offs = _b->buf_info.offset;
+ mapped_size = 0;
+ for (i = 0; i < b->num_blocks; i++, blk_offs += blk_size) {
+ blk_size = tiler_size(&_b->mi[i]->blk);
+ if (offs >= blk_offs + blk_size || offs + size < blk_offs)
+ continue;
+ map_offs = max(offs, blk_offs) - blk_offs;
+ map_size = min(size - mapped_size, blk_size);
+ if (tiler_mmap_blk(&_b->mi[i]->blk, map_offs, map_size, vma,
+ mapped_size))
+ return -EAGAIN;
+ mapped_size += map_size;
}
return 0;
}