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 /drivers/media/video/videobuf-dma-sg.c | |
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>
Diffstat (limited to 'drivers/media/video/videobuf-dma-sg.c')
-rw-r--r-- | drivers/media/video/videobuf-dma-sg.c | 17 |
1 files changed, 9 insertions, 8 deletions
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; |