Added patches by freemangordon:
[kernel-power] / kernel-power-2.6.28 / debian / patches / videobuf-dma-sg-support-non-pagable-user-memory.diff
1 --- a/drivers/media/video/videobuf-dma-sg.c     2011-11-15 06:09:03.031835263 -0500
2 +++ b/drivers/media/video/videobuf-dma-sg.c     2011-12-28 07:50:34.514877000 -0500
3 @@ -137,6 +137,7 @@
4  {
5         unsigned long first,last;
6         int err, rw = 0;
7 +       struct vm_area_struct *vma;
8  
9         dma->direction = direction;
10         switch (dma->direction) {
11 @@ -154,6 +155,23 @@
12         last  = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
13         dma->offset   = data & ~PAGE_MASK;
14         dma->nr_pages = last-first+1;
15 +
16 +       /* In case the buffer is user-allocated and is actually an IO buffer for
17 +          some other hardware, we cannot map pages for it.  It in fact behaves
18 +          the same as an overlay. */
19 +       vma = find_vma (current->mm, data);
20 +       if (vma && (vma->vm_flags & VM_IO)) {
21 +               /* Only a single contiguous buffer is supported. */
22 +               if (vma->vm_end < data + size) {
23 +                       dprintk(1, "init user: non-contiguous IO buffer.\n");
24 +                       return -EFAULT; /* same error that get_user_pages() would give */
25 +               }
26 +               dma->bus_addr = (vma->vm_pgoff << PAGE_SHIFT) + (data - vma->vm_start);
27 +               dprintk(1,"init user IO [0x%lx+0x%lx => %d pages at 0x%x]\n",
28 +                       data, size, dma->nr_pages, dma->bus_addr);
29 +               return 0;
30 +       }
31 +
32         dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
33                              GFP_KERNEL);
34         if (NULL == dma->pages)
35 @@ -231,12 +249,27 @@
36                                                 (dma->vmalloc,dma->nr_pages);
37         }
38         if (dma->bus_addr) {
39 -               dma->sglist = vmalloc(sizeof(*dma->sglist));
40 +               unsigned long physp=dma->bus_addr;
41 +               int i,len;
42 +
43 +               len=dma->nr_pages;
44 +               dma->sglist = vmalloc(len*sizeof(*dma->sglist));
45 +               sg_init_table(dma->sglist, len);
46                 if (NULL != dma->sglist) {
47 -                       dma->sglen  = 1;
48 -                       sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
49 -                       dma->sglist[0].offset           = dma->bus_addr & ~PAGE_MASK;
50 -                       sg_dma_len(&dma->sglist[0])     = dma->nr_pages * PAGE_SIZE;
51 +                       dma->sglist[0].offset           = dma->bus_addr & ~PAGE_MASK;
52 +                       sg_dma_len(&dma->sglist[0])     = PAGE_SIZE - dma->offset;
53 +                       sg_dma_address(&dma->sglist[0]) = (dma_addr_t)physp & PAGE_MASK;
54 +                       physp += sg_dma_len(&dma->sglist[0]);
55 +                       /*
56 +                        * Iterate in a loop for the number of pages
57 +                        */
58 +                       for (i = 1; i < len; i++) {
59 +                               dma->sglist[i].offset           = 0;
60 +                               sg_dma_len(&dma->sglist[i])     = PAGE_SIZE;
61 +                               sg_dma_address(&dma->sglist[i]) = (dma_addr_t)physp;
62 +                               physp += PAGE_SIZE;
63 +                       }
64 +                       dma->sglen = len;
65                 }
66         }
67         if (NULL == dma->sglist) {
68 @@ -263,7 +296,7 @@
69         MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
70         BUG_ON(!dma->sglen);
71  
72 -       dma_sync_sg_for_cpu(q->dev, dma->sglist, dma->nr_pages, dma->direction);
73 +       dma_sync_sg_for_cpu(q->dev, dma->sglist, dma->sglen, dma->direction);
74         return 0;
75  }
76  
77 @@ -273,7 +306,7 @@
78         if (!dma->sglen)
79                 return 0;
80  
81 -       dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
82 +       dma_unmap_sg(q->dev, dma->sglist, dma->sglen, dma->direction);
83  
84         vfree(dma->sglist);
85         dma->sglist = NULL;