diff options
| author | Cohen David.A <david.cohen@nokia.com> | 2009-05-11 10:00:20 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-16 17:21:10 -0400 |
| commit | 1010ed132727bbf486ac28fd149ccfb0ef5cd2ab (patch) | |
| tree | aa95ea2fb7cc5aec23c83ea650e8397a593d1c8d | |
| parent | 04a37e0f32f9882430bc1899899d2ed91b8aaf5b (diff) | |
V4L/DVB (11840): change kmalloc to vmalloc for sglist allocation in videobuf_dma_map/unmap
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>
| -rw-r--r-- | Documentation/video4linux/CARDLIST.em28xx | 2 | ||||
| -rw-r--r-- | drivers/media/video/videobuf-dma-sg.c | 17 |
2 files changed, 11 insertions, 8 deletions
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index bf58d957e0df..20aa65a7059c 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx | |||
| @@ -62,3 +62,5 @@ | |||
| 62 | 64 -> Easy Cap Capture DC-60 (em2860) | 62 | 64 -> Easy Cap Capture DC-60 (em2860) |
| 63 | 65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515] | 63 | 65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515] |
| 64 | 66 -> Empire dual TV (em2880) | 64 | 66 -> Empire dual TV (em2880) |
| 65 | 67 -> Terratec Grabby (em2860) [0ccd:0096] | ||
| 66 | 68 -> Terratec AV350 (em2860) [0ccd:0084] | ||
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index da1790e57a86..c9a5d7edbe4e 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c | |||
| @@ -58,9 +58,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) | |||
| 58 | struct page *pg; | 58 | struct page *pg; |
| 59 | int i; | 59 | int i; |
| 60 | 60 | ||
| 61 | sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); | 61 | sglist = vmalloc(nr_pages * sizeof(*sglist)); |
| 62 | if (NULL == sglist) | 62 | if (NULL == sglist) |
| 63 | return NULL; | 63 | return NULL; |
| 64 | memset(sglist, 0, nr_pages * sizeof(*sglist)); | ||
| 64 | sg_init_table(sglist, nr_pages); | 65 | sg_init_table(sglist, nr_pages); |
| 65 | for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { | 66 | for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { |
| 66 | pg = vmalloc_to_page(virt); | 67 | pg = vmalloc_to_page(virt); |
| @@ -72,7 +73,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) | |||
| 72 | return sglist; | 73 | return sglist; |
| 73 | 74 | ||
| 74 | err: | 75 | err: |
| 75 | kfree(sglist); | 76 | vfree(sglist); |
| 76 | return NULL; | 77 | return NULL; |
| 77 | } | 78 | } |
| 78 | 79 | ||
| @@ -84,7 +85,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) | |||
| 84 | 85 | ||
| 85 | if (NULL == pages[0]) | 86 | if (NULL == pages[0]) |
| 86 | return NULL; | 87 | return NULL; |
| 87 | sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL); | 88 | sglist = vmalloc(nr_pages * sizeof(*sglist)); |
| 88 | if (NULL == sglist) | 89 | if (NULL == sglist) |
| 89 | return NULL; | 90 | return NULL; |
| 90 | sg_init_table(sglist, nr_pages); | 91 | sg_init_table(sglist, nr_pages); |
| @@ -104,12 +105,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) | |||
| 104 | 105 | ||
| 105 | nopage: | 106 | nopage: |
| 106 | dprintk(2,"sgl: oops - no page\n"); | 107 | dprintk(2,"sgl: oops - no page\n"); |
| 107 | kfree(sglist); | 108 | vfree(sglist); |
| 108 | return NULL; | 109 | return NULL; |
| 109 | 110 | ||
| 110 | highmem: | 111 | highmem: |
| 111 | dprintk(2,"sgl: oops - highmem page\n"); | 112 | dprintk(2,"sgl: oops - highmem page\n"); |
| 112 | kfree(sglist); | 113 | vfree(sglist); |
| 113 | return NULL; | 114 | return NULL; |
| 114 | } | 115 | } |
| 115 | 116 | ||
| @@ -230,7 +231,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) | |||
| 230 | (dma->vmalloc,dma->nr_pages); | 231 | (dma->vmalloc,dma->nr_pages); |
| 231 | } | 232 | } |
| 232 | if (dma->bus_addr) { | 233 | if (dma->bus_addr) { |
| 233 | dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); | 234 | dma->sglist = vmalloc(sizeof(*dma->sglist)); |
| 234 | if (NULL != dma->sglist) { | 235 | if (NULL != dma->sglist) { |
| 235 | dma->sglen = 1; | 236 | dma->sglen = 1; |
| 236 | sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; | 237 | 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) | |||
| 248 | if (0 == dma->sglen) { | 249 | if (0 == dma->sglen) { |
| 249 | printk(KERN_WARNING | 250 | printk(KERN_WARNING |
| 250 | "%s: videobuf_map_sg failed\n",__func__); | 251 | "%s: videobuf_map_sg failed\n",__func__); |
| 251 | kfree(dma->sglist); | 252 | vfree(dma->sglist); |
| 252 | dma->sglist = NULL; | 253 | dma->sglist = NULL; |
| 253 | dma->sglen = 0; | 254 | dma->sglen = 0; |
| 254 | return -EIO; | 255 | return -EIO; |
| @@ -274,7 +275,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) | |||
| 274 | 275 | ||
| 275 | dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); | 276 | dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); |
| 276 | 277 | ||
| 277 | kfree(dma->sglist); | 278 | vfree(dma->sglist); |
| 278 | dma->sglist = NULL; | 279 | dma->sglist = NULL; |
| 279 | dma->sglen = 0; | 280 | dma->sglen = 0; |
| 280 | return 0; | 281 | return 0; |
