diff mbox

[2/2] V4L/DVB: buf-dma-sg.c: support non-pageable user-allocated memory

Message ID 1267718451-24961-3-git-send-email-arnout@mind.be (mailing list archive)
State Superseded
Headers show

Commit Message

Arnout Vandecappelle March 4, 2010, 4 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 3b6f1b8..7884207 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -136,6 +136,7 @@  static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
 {
 	unsigned long first,last;
 	int err, rw = 0;
+	struct vm_area_struct *vma;
 
 	dma->direction = direction;
 	switch (dma->direction) {
@@ -153,6 +154,23 @@  static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
 	last  = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
 	dma->offset   = data & ~PAGE_MASK;
 	dma->nr_pages = last-first+1;
+
+	/* In case the buffer is user-allocated and is actually an IO buffer for
+	   some other hardware, we cannot map pages for it.  It in fact behaves
+	   the same as an overlay. */
+	vma = find_vma (current->mm, data);
+	if (vma && (vma->vm_flags & VM_IO)) {
+		/* Only a single contiguous buffer is supported. */
+		if (vma->vm_end < data + size) {
+			dprintk(1, "init user: non-contiguous IO buffer.\n");
+			return -EFAULT; /* same error that get_user_pages() would give */
+		}
+		dma->bus_addr = (vma->vm_pgoff << PAGE_SHIFT) +	(data - vma->vm_start);
+		dprintk(1,"init user IO [0x%lx+0x%lx => %d pages at 0x%x]\n",
+			data, size, dma->nr_pages, dma->bus_addr);
+		return 0;
+	}
+
 	dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
 			     GFP_KERNEL);
 	if (NULL == dma->pages)