videobuf2-vmalloc.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
  3. *
  4. * Copyright (C) 2010 Samsung Electronics
  5. *
  6. * Author: Pawel Osciak <pawel@osciak.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/mm.h>
  14. #include <linux/slab.h>
  15. #include <linux/vmalloc.h>
  16. #include <media/videobuf2-core.h>
  17. #include <media/videobuf2-memops.h>
  18. struct vb2_vmalloc_buf {
  19. void *vaddr;
  20. unsigned long size;
  21. atomic_t refcount;
  22. struct vb2_vmarea_handler handler;
  23. };
  24. static void vb2_vmalloc_put(void *buf_priv);
  25. static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
  26. {
  27. struct vb2_vmalloc_buf *buf;
  28. buf = kzalloc(sizeof *buf, GFP_KERNEL);
  29. if (!buf)
  30. return NULL;
  31. buf->size = size;
  32. buf->vaddr = vmalloc_user(buf->size);
  33. buf->handler.refcount = &buf->refcount;
  34. buf->handler.put = vb2_vmalloc_put;
  35. buf->handler.arg = buf;
  36. if (!buf->vaddr) {
  37. printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
  38. kfree(buf);
  39. return NULL;
  40. }
  41. atomic_inc(&buf->refcount);
  42. printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
  43. buf->size, buf->vaddr);
  44. return buf;
  45. }
  46. static void vb2_vmalloc_put(void *buf_priv)
  47. {
  48. struct vb2_vmalloc_buf *buf = buf_priv;
  49. if (atomic_dec_and_test(&buf->refcount)) {
  50. printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
  51. __func__, buf->vaddr);
  52. vfree(buf->vaddr);
  53. kfree(buf);
  54. }
  55. }
  56. static void *vb2_vmalloc_vaddr(void *buf_priv)
  57. {
  58. struct vb2_vmalloc_buf *buf = buf_priv;
  59. BUG_ON(!buf);
  60. if (!buf->vaddr) {
  61. printk(KERN_ERR "Address of an unallocated plane requested\n");
  62. return NULL;
  63. }
  64. return buf->vaddr;
  65. }
  66. static unsigned int vb2_vmalloc_num_users(void *buf_priv)
  67. {
  68. struct vb2_vmalloc_buf *buf = buf_priv;
  69. return atomic_read(&buf->refcount);
  70. }
  71. static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
  72. {
  73. struct vb2_vmalloc_buf *buf = buf_priv;
  74. int ret;
  75. if (!buf) {
  76. printk(KERN_ERR "No memory to map\n");
  77. return -EINVAL;
  78. }
  79. ret = remap_vmalloc_range(vma, buf->vaddr, 0);
  80. if (ret) {
  81. printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
  82. return ret;
  83. }
  84. /*
  85. * Make sure that vm_areas for 2 buffers won't be merged together
  86. */
  87. vma->vm_flags |= VM_DONTEXPAND;
  88. /*
  89. * Use common vm_area operations to track buffer refcount.
  90. */
  91. vma->vm_private_data = &buf->handler;
  92. vma->vm_ops = &vb2_common_vm_ops;
  93. vma->vm_ops->open(vma);
  94. return 0;
  95. }
  96. const struct vb2_mem_ops vb2_vmalloc_memops = {
  97. .alloc = vb2_vmalloc_alloc,
  98. .put = vb2_vmalloc_put,
  99. .vaddr = vb2_vmalloc_vaddr,
  100. .mmap = vb2_vmalloc_mmap,
  101. .num_users = vb2_vmalloc_num_users,
  102. };
  103. EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
  104. MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
  105. MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
  106. MODULE_LICENSE("GPL");