aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-01-06 13:30:03 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-25 10:14:43 -0400
commit8271601aca19c1d0ad29d0b65a5a6b9e6ef97bd3 (patch)
tree7d426c119eb97ddd7a07faee90bd988487d825a5
parent73c1ea496cf79aec8a5681064719703b346301dc (diff)
[media] omap3isp: queue: Merge the prepare and sglist functions
In preparation for the switch to the DMA API merge the two functions that handle buffer preparation for the USERPTR cases (both page-backed and non page-backed memory). Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Sakari Ailus <sakari.ailus@iki.fi> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.c169
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.h4
2 files changed, 69 insertions, 104 deletions
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c
index 51ec40d6ea42..a7be7d7d5db5 100644
--- a/drivers/media/platform/omap3isp/ispqueue.c
+++ b/drivers/media/platform/omap3isp/ispqueue.c
@@ -178,12 +178,12 @@ out:
178} 178}
179 179
180/* 180/*
181 * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer 181 * isp_video_buffer_prepare_kernel - Build scatter list for a vmalloc'ed buffer
182 * 182 *
183 * Iterate over the vmalloc'ed area and create a scatter list entry for every 183 * Iterate over the vmalloc'ed area and create a scatter list entry for every
184 * page. 184 * page.
185 */ 185 */
186static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf) 186static int isp_video_buffer_prepare_kernel(struct isp_video_buffer *buf)
187{ 187{
188 struct scatterlist *sg; 188 struct scatterlist *sg;
189 unsigned int npages; 189 unsigned int npages;
@@ -214,67 +214,6 @@ static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf)
214} 214}
215 215
216/* 216/*
217 * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer
218 *
219 * Walk the buffer pages list and create a 1:1 mapping to a scatter list.
220 */
221static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf)
222{
223 unsigned int offset = buf->offset;
224 struct scatterlist *sg;
225 unsigned int i;
226 int ret;
227
228 ret = sg_alloc_table(&buf->sgt, buf->npages, GFP_KERNEL);
229 if (ret < 0)
230 return ret;
231
232 for (sg = buf->sgt.sgl, i = 0; i < buf->npages; ++i) {
233 if (PageHighMem(buf->pages[i])) {
234 sg_free_table(&buf->sgt);
235 return -EINVAL;
236 }
237
238 sg_set_page(sg, buf->pages[i], PAGE_SIZE - offset, offset);
239 sg = sg_next(sg);
240 offset = 0;
241 }
242
243 return 0;
244}
245
246/*
247 * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer
248 *
249 * Create a scatter list of physically contiguous pages starting at the buffer
250 * memory physical address.
251 */
252static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf)
253{
254 struct scatterlist *sg;
255 unsigned int offset = buf->offset;
256 unsigned long pfn = buf->paddr >> PAGE_SHIFT;
257 unsigned int i;
258 int ret;
259
260 ret = sg_alloc_table(&buf->sgt, buf->npages, GFP_KERNEL);
261 if (ret < 0)
262 return ret;
263
264 for (sg = buf->sgt.sgl, i = 0; i < buf->npages; ++i, ++pfn) {
265 sg_set_page(sg, pfn_to_page(pfn), PAGE_SIZE - offset, offset);
266 /* PFNMAP buffers will not get DMA-mapped, set the DMA address
267 * manually.
268 */
269 sg_dma_address(sg) = (pfn << PAGE_SHIFT) + offset;
270 sg = sg_next(sg);
271 offset = 0;
272 }
273
274 return 0;
275}
276
277/*
278 * isp_video_buffer_cleanup - Release pages for a userspace VMA. 217 * isp_video_buffer_cleanup - Release pages for a userspace VMA.
279 * 218 *
280 * Release pages locked by a call isp_video_buffer_prepare_user and free the 219 * Release pages locked by a call isp_video_buffer_prepare_user and free the
@@ -316,11 +255,11 @@ static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
316} 255}
317 256
318/* 257/*
319 * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory. 258 * isp_video_buffer_prepare_user - Prepare a userspace buffer.
320 * 259 *
321 * This function creates a list of pages for a userspace VMA. The number of 260 * This function creates a scatter list with a 1:1 mapping for a userspace VMA.
322 * pages is first computed based on the buffer size, and pages are then 261 * The number of pages is first computed based on the buffer size, and pages are
323 * retrieved by a call to get_user_pages. 262 * then retrieved by a call to get_user_pages.
324 * 263 *
325 * Pages are pinned to memory by get_user_pages, making them available for DMA 264 * Pages are pinned to memory by get_user_pages, making them available for DMA
326 * transfers. However, due to memory management optimization, it seems the 265 * transfers. However, due to memory management optimization, it seems the
@@ -340,16 +279,19 @@ static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
340 */ 279 */
341static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) 280static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
342{ 281{
282 struct scatterlist *sg;
283 unsigned int offset;
343 unsigned long data; 284 unsigned long data;
344 unsigned int first; 285 unsigned int first;
345 unsigned int last; 286 unsigned int last;
287 unsigned int i;
346 int ret; 288 int ret;
347 289
348 data = buf->vbuf.m.userptr; 290 data = buf->vbuf.m.userptr;
349 first = (data & PAGE_MASK) >> PAGE_SHIFT; 291 first = (data & PAGE_MASK) >> PAGE_SHIFT;
350 last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT; 292 last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT;
293 offset = data & ~PAGE_MASK;
351 294
352 buf->offset = data & ~PAGE_MASK;
353 buf->npages = last - first + 1; 295 buf->npages = last - first + 1;
354 buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0])); 296 buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0]));
355 if (buf->pages == NULL) 297 if (buf->pages == NULL)
@@ -364,68 +306,104 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
364 306
365 if (ret != buf->npages) { 307 if (ret != buf->npages) {
366 buf->npages = ret < 0 ? 0 : ret; 308 buf->npages = ret < 0 ? 0 : ret;
367 isp_video_buffer_cleanup(buf);
368 return -EFAULT; 309 return -EFAULT;
369 } 310 }
370 311
371 ret = isp_video_buffer_lock_vma(buf, 1); 312 ret = isp_video_buffer_lock_vma(buf, 1);
372 if (ret < 0) 313 if (ret < 0)
373 isp_video_buffer_cleanup(buf); 314 return ret;
374 315
375 return ret; 316 ret = sg_alloc_table(&buf->sgt, buf->npages, GFP_KERNEL);
317 if (ret < 0)
318 return ret;
319
320 for (sg = buf->sgt.sgl, i = 0; i < buf->npages; ++i) {
321 if (PageHighMem(buf->pages[i])) {
322 sg_free_table(&buf->sgt);
323 return -EINVAL;
324 }
325
326 sg_set_page(sg, buf->pages[i], PAGE_SIZE - offset, offset);
327 sg = sg_next(sg);
328 offset = 0;
329 }
330
331 return 0;
376} 332}
377 333
378/* 334/*
379 * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer 335 * isp_video_buffer_prepare_pfnmap - Prepare a VM_PFNMAP userspace buffer
380 * 336 *
381 * Userspace VM_PFNMAP buffers are supported only if they are contiguous in 337 * Userspace VM_PFNMAP buffers are supported only if they are contiguous in
382 * memory and if they span a single VMA. 338 * memory and if they span a single VMA. Start by validating the user pointer to
339 * make sure it fulfils that condition, and then build a scatter list of
340 * physically contiguous pages starting at the buffer memory physical address.
383 * 341 *
384 * Return 0 if the buffer is valid, or -EFAULT otherwise. 342 * Return 0 on success, -EFAULT if the buffer isn't valid or -ENOMEM if memory
343 * can't be allocated.
385 */ 344 */
386static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf) 345static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf)
387{ 346{
388 struct vm_area_struct *vma; 347 struct vm_area_struct *vma;
348 struct scatterlist *sg;
389 unsigned long prev_pfn; 349 unsigned long prev_pfn;
390 unsigned long this_pfn; 350 unsigned long this_pfn;
391 unsigned long start; 351 unsigned long start;
352 unsigned int offset;
392 unsigned long end; 353 unsigned long end;
393 dma_addr_t pa = 0; 354 unsigned long pfn;
394 int ret = -EFAULT; 355 unsigned int i;
356 int ret = 0;
395 357
396 start = buf->vbuf.m.userptr; 358 start = buf->vbuf.m.userptr;
397 end = buf->vbuf.m.userptr + buf->vbuf.length - 1; 359 end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
360 offset = start & ~PAGE_MASK;
398 361
399 buf->offset = start & ~PAGE_MASK;
400 buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; 362 buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
401 buf->pages = NULL; 363 buf->pages = NULL;
402 364
403 down_read(&current->mm->mmap_sem); 365 down_read(&current->mm->mmap_sem);
404 vma = find_vma(current->mm, start); 366 vma = find_vma(current->mm, start);
405 if (vma == NULL || vma->vm_end < end) 367 if (vma == NULL || vma->vm_end < end) {
406 goto done; 368 ret = -EFAULT;
369 goto unlock;
370 }
407 371
408 for (prev_pfn = 0; start <= end; start += PAGE_SIZE) { 372 for (prev_pfn = 0; start <= end; start += PAGE_SIZE) {
409 ret = follow_pfn(vma, start, &this_pfn); 373 ret = follow_pfn(vma, start, &this_pfn);
410 if (ret) 374 if (ret < 0)
411 goto done; 375 goto unlock;
412 376
413 if (prev_pfn == 0) 377 if (prev_pfn == 0)
414 pa = this_pfn << PAGE_SHIFT; 378 pfn = this_pfn;
415 else if (this_pfn != prev_pfn + 1) { 379 else if (this_pfn != prev_pfn + 1) {
416 ret = -EFAULT; 380 ret = -EFAULT;
417 goto done; 381 goto unlock;
418 } 382 }
419 383
420 prev_pfn = this_pfn; 384 prev_pfn = this_pfn;
421 } 385 }
422 386
423 buf->paddr = pa + buf->offset; 387unlock:
424 ret = 0;
425
426done:
427 up_read(&current->mm->mmap_sem); 388 up_read(&current->mm->mmap_sem);
428 return ret; 389 if (ret < 0)
390 return ret;
391
392 ret = sg_alloc_table(&buf->sgt, buf->npages, GFP_KERNEL);
393 if (ret < 0)
394 return ret;
395
396 for (sg = buf->sgt.sgl, i = 0; i < buf->npages; ++i, ++pfn) {
397 sg_set_page(sg, pfn_to_page(pfn), PAGE_SIZE - offset, offset);
398 /* PFNMAP buffers will not get DMA-mapped, set the DMA address
399 * manually.
400 */
401 sg_dma_address(sg) = (pfn << PAGE_SHIFT) + offset;
402 sg = sg_next(sg);
403 offset = 0;
404 }
405
406 return 0;
429} 407}
430 408
431/* 409/*
@@ -511,7 +489,7 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
511 489
512 switch (buf->vbuf.memory) { 490 switch (buf->vbuf.memory) {
513 case V4L2_MEMORY_MMAP: 491 case V4L2_MEMORY_MMAP:
514 ret = isp_video_buffer_sglist_kernel(buf); 492 ret = isp_video_buffer_prepare_kernel(buf);
515 break; 493 break;
516 494
517 case V4L2_MEMORY_USERPTR: 495 case V4L2_MEMORY_USERPTR:
@@ -519,19 +497,10 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
519 if (ret < 0) 497 if (ret < 0)
520 return ret; 498 return ret;
521 499
522 if (buf->vm_flags & VM_PFNMAP) { 500 if (buf->vm_flags & VM_PFNMAP)
523 ret = isp_video_buffer_prepare_pfnmap(buf); 501 ret = isp_video_buffer_prepare_pfnmap(buf);
524 if (ret < 0) 502 else
525 return ret;
526
527 ret = isp_video_buffer_sglist_pfnmap(buf);
528 } else {
529 ret = isp_video_buffer_prepare_user(buf); 503 ret = isp_video_buffer_prepare_user(buf);
530 if (ret < 0)
531 return ret;
532
533 ret = isp_video_buffer_sglist_user(buf);
534 }
535 break; 504 break;
536 505
537 default: 506 default:
diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h
index 99c11e8c6e9d..f78325dbcf49 100644
--- a/drivers/media/platform/omap3isp/ispqueue.h
+++ b/drivers/media/platform/omap3isp/ispqueue.h
@@ -69,10 +69,8 @@ enum isp_video_buffer_state {
69 * @skip_cache: Whether to skip cache management operations for this buffer 69 * @skip_cache: Whether to skip cache management operations for this buffer
70 * @vaddr: Memory virtual address (for kernel buffers) 70 * @vaddr: Memory virtual address (for kernel buffers)
71 * @vm_flags: Buffer VMA flags (for userspace buffers) 71 * @vm_flags: Buffer VMA flags (for userspace buffers)
72 * @offset: Offset inside the first page (for userspace buffers)
73 * @npages: Number of pages (for userspace buffers) 72 * @npages: Number of pages (for userspace buffers)
74 * @pages: Pages table (for userspace non-VM_PFNMAP buffers) 73 * @pages: Pages table (for userspace non-VM_PFNMAP buffers)
75 * @paddr: Memory physical address (for userspace VM_PFNMAP buffers)
76 * @sgt: Scatter gather table (for non-VM_PFNMAP buffers) 74 * @sgt: Scatter gather table (for non-VM_PFNMAP buffers)
77 * @vbuf: V4L2 buffer 75 * @vbuf: V4L2 buffer
78 * @irqlist: List head for insertion into IRQ queue 76 * @irqlist: List head for insertion into IRQ queue
@@ -91,10 +89,8 @@ struct isp_video_buffer {
91 89
92 /* For userspace buffers. */ 90 /* For userspace buffers. */
93 vm_flags_t vm_flags; 91 vm_flags_t vm_flags;
94 unsigned long offset;
95 unsigned int npages; 92 unsigned int npages;
96 struct page **pages; 93 struct page **pages;
97 dma_addr_t paddr;
98 94
99 /* For all buffers except VM_PFNMAP. */ 95 /* For all buffers except VM_PFNMAP. */
100 struct sg_table sgt; 96 struct sg_table sgt;