V4L/DVB (11840): change kmalloc to vmalloc for sglist allocation in videobuf_dma_map...
Cohen David.A [Mon, 11 May 2009 14:00:20 +0000 (11:00 -0300)]
Change kmalloc()/kfree() to vmalloc()/vfree() for sglist allocation
during videobuf_dma_map() and videobuf_dma_unmap()

High resolution sensors might require too many contiguous pages
to be allocated for sglist by kmalloc() during videobuf_dma_map()
(i.e. 256Kib for 8MP sensor).
In such situations, kmalloc() could face some problem to find the
required free memory. vmalloc() is a safer solution instead, as the
allocated memory does not need to be contiguous.

Signed-off-by: David Cohen <david.cohen@nokia.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

Documentation/video4linux/CARDLIST.em28xx
drivers/media/video/videobuf-dma-sg.c

index bf58d95..20aa65a 100644 (file)
@@ -62,3 +62,5 @@
  64 -> Easy Cap Capture DC-60                   (em2860)
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
  66 -> Empire dual TV                           (em2880)
+ 67 -> Terratec Grabby                          (em2860)        [0ccd:0096]
+ 68 -> Terratec AV350                           (em2860)        [0ccd:0084]
index da1790e..c9a5d7e 100644 (file)
@@ -58,9 +58,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
        struct page *pg;
        int i;
 
-       sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+       sglist = vmalloc(nr_pages * sizeof(*sglist));
        if (NULL == sglist)
                return NULL;
+       memset(sglist, 0, nr_pages * sizeof(*sglist));
        sg_init_table(sglist, nr_pages);
        for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
                pg = vmalloc_to_page(virt);
@@ -72,7 +73,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
        return sglist;
 
  err:
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 }
 
@@ -84,7 +85,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 
        if (NULL == pages[0])
                return NULL;
-       sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL);
+       sglist = vmalloc(nr_pages * sizeof(*sglist));
        if (NULL == sglist)
                return NULL;
        sg_init_table(sglist, nr_pages);
@@ -104,12 +105,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 
  nopage:
        dprintk(2,"sgl: oops - no page\n");
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 
  highmem:
        dprintk(2,"sgl: oops - highmem page\n");
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 }
 
@@ -230,7 +231,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
                                                (dma->vmalloc,dma->nr_pages);
        }
        if (dma->bus_addr) {
-               dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
+               dma->sglist = vmalloc(sizeof(*dma->sglist));
                if (NULL != dma->sglist) {
                        dma->sglen  = 1;
                        sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
@@ -248,7 +249,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
                if (0 == dma->sglen) {
                        printk(KERN_WARNING
                               "%s: videobuf_map_sg failed\n",__func__);
-                       kfree(dma->sglist);
+                       vfree(dma->sglist);
                        dma->sglist = NULL;
                        dma->sglen = 0;
                        return -EIO;
@@ -274,7 +275,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
 
        dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
 
-       kfree(dma->sglist);
+       vfree(dma->sglist);
        dma->sglist = NULL;
        dma->sglen = 0;
        return 0;