vkms_gem.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. */
  8. #include <linux/shmem_fs.h>
  9. #include "vkms_drv.h"
  10. static struct vkms_gem_object *__vkms_gem_create(struct drm_device *dev,
  11. u64 size)
  12. {
  13. struct vkms_gem_object *obj;
  14. int ret;
  15. obj = kzalloc(sizeof(*obj), GFP_KERNEL);
  16. if (!obj)
  17. return ERR_PTR(-ENOMEM);
  18. size = roundup(size, PAGE_SIZE);
  19. ret = drm_gem_object_init(dev, &obj->gem, size);
  20. if (ret) {
  21. kfree(obj);
  22. return ERR_PTR(ret);
  23. }
  24. mutex_init(&obj->pages_lock);
  25. return obj;
  26. }
  27. void vkms_gem_free_object(struct drm_gem_object *obj)
  28. {
  29. struct vkms_gem_object *gem = container_of(obj, struct vkms_gem_object,
  30. gem);
  31. WARN_ON(gem->pages);
  32. WARN_ON(gem->vaddr);
  33. mutex_destroy(&gem->pages_lock);
  34. drm_gem_object_release(obj);
  35. kfree(gem);
  36. }
  37. vm_fault_t vkms_gem_fault(struct vm_fault *vmf)
  38. {
  39. struct vm_area_struct *vma = vmf->vma;
  40. struct vkms_gem_object *obj = vma->vm_private_data;
  41. unsigned long vaddr = vmf->address;
  42. pgoff_t page_offset;
  43. loff_t num_pages;
  44. vm_fault_t ret = VM_FAULT_SIGBUS;
  45. page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT;
  46. num_pages = DIV_ROUND_UP(obj->gem.size, PAGE_SIZE);
  47. if (page_offset > num_pages)
  48. return VM_FAULT_SIGBUS;
  49. mutex_lock(&obj->pages_lock);
  50. if (obj->pages) {
  51. get_page(obj->pages[page_offset]);
  52. vmf->page = obj->pages[page_offset];
  53. ret = 0;
  54. }
  55. mutex_unlock(&obj->pages_lock);
  56. if (ret) {
  57. struct page *page;
  58. struct address_space *mapping;
  59. mapping = file_inode(obj->gem.filp)->i_mapping;
  60. page = shmem_read_mapping_page(mapping, page_offset);
  61. if (!IS_ERR(page)) {
  62. vmf->page = page;
  63. ret = 0;
  64. } else {
  65. switch (PTR_ERR(page)) {
  66. case -ENOSPC:
  67. case -ENOMEM:
  68. ret = VM_FAULT_OOM;
  69. break;
  70. case -EBUSY:
  71. ret = VM_FAULT_RETRY;
  72. break;
  73. case -EFAULT:
  74. case -EINVAL:
  75. ret = VM_FAULT_SIGBUS;
  76. break;
  77. default:
  78. WARN_ON(PTR_ERR(page));
  79. ret = VM_FAULT_SIGBUS;
  80. break;
  81. }
  82. }
  83. }
  84. return ret;
  85. }
  86. struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
  87. struct drm_file *file,
  88. u32 *handle,
  89. u64 size)
  90. {
  91. struct vkms_gem_object *obj;
  92. int ret;
  93. if (!file || !dev || !handle)
  94. return ERR_PTR(-EINVAL);
  95. obj = __vkms_gem_create(dev, size);
  96. if (IS_ERR(obj))
  97. return ERR_CAST(obj);
  98. ret = drm_gem_handle_create(file, &obj->gem, handle);
  99. drm_gem_object_put_unlocked(&obj->gem);
  100. if (ret) {
  101. drm_gem_object_release(&obj->gem);
  102. kfree(obj);
  103. return ERR_PTR(ret);
  104. }
  105. return &obj->gem;
  106. }
  107. int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
  108. struct drm_mode_create_dumb *args)
  109. {
  110. struct drm_gem_object *gem_obj;
  111. u64 pitch, size;
  112. if (!args || !dev || !file)
  113. return -EINVAL;
  114. pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
  115. size = pitch * args->height;
  116. if (!size)
  117. return -EINVAL;
  118. gem_obj = vkms_gem_create(dev, file, &args->handle, size);
  119. if (IS_ERR(gem_obj))
  120. return PTR_ERR(gem_obj);
  121. args->size = gem_obj->size;
  122. args->pitch = pitch;
  123. DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
  124. return 0;
  125. }
  126. int vkms_dumb_map(struct drm_file *file, struct drm_device *dev,
  127. u32 handle, u64 *offset)
  128. {
  129. struct drm_gem_object *obj;
  130. int ret;
  131. obj = drm_gem_object_lookup(file, handle);
  132. if (!obj)
  133. return -ENOENT;
  134. if (!obj->filp) {
  135. ret = -EINVAL;
  136. goto unref;
  137. }
  138. ret = drm_gem_create_mmap_offset(obj);
  139. if (ret)
  140. goto unref;
  141. *offset = drm_vma_node_offset_addr(&obj->vma_node);
  142. unref:
  143. drm_gem_object_put_unlocked(obj);
  144. return ret;
  145. }
  146. static struct page **_get_pages(struct vkms_gem_object *vkms_obj)
  147. {
  148. struct drm_gem_object *gem_obj = &vkms_obj->gem;
  149. if (!vkms_obj->pages) {
  150. struct page **pages = drm_gem_get_pages(gem_obj);
  151. if (IS_ERR(pages))
  152. return pages;
  153. if (cmpxchg(&vkms_obj->pages, NULL, pages))
  154. drm_gem_put_pages(gem_obj, pages, false, true);
  155. }
  156. return vkms_obj->pages;
  157. }
  158. void vkms_gem_vunmap(struct drm_gem_object *obj)
  159. {
  160. struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(obj);
  161. mutex_lock(&vkms_obj->pages_lock);
  162. if (vkms_obj->vmap_count < 1) {
  163. WARN_ON(vkms_obj->vaddr);
  164. WARN_ON(vkms_obj->pages);
  165. mutex_unlock(&vkms_obj->pages_lock);
  166. return;
  167. }
  168. vkms_obj->vmap_count--;
  169. if (vkms_obj->vmap_count == 0) {
  170. vunmap(vkms_obj->vaddr);
  171. vkms_obj->vaddr = NULL;
  172. drm_gem_put_pages(obj, vkms_obj->pages, false, true);
  173. vkms_obj->pages = NULL;
  174. }
  175. mutex_unlock(&vkms_obj->pages_lock);
  176. }
  177. int vkms_gem_vmap(struct drm_gem_object *obj)
  178. {
  179. struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(obj);
  180. int ret = 0;
  181. mutex_lock(&vkms_obj->pages_lock);
  182. if (!vkms_obj->vaddr) {
  183. unsigned int n_pages = obj->size >> PAGE_SHIFT;
  184. struct page **pages = _get_pages(vkms_obj);
  185. if (IS_ERR(pages)) {
  186. ret = PTR_ERR(pages);
  187. goto out;
  188. }
  189. vkms_obj->vaddr = vmap(pages, n_pages, VM_MAP, PAGE_KERNEL);
  190. if (!vkms_obj->vaddr)
  191. goto err_vmap;
  192. }
  193. vkms_obj->vmap_count++;
  194. goto out;
  195. err_vmap:
  196. ret = -ENOMEM;
  197. drm_gem_put_pages(obj, vkms_obj->pages, false, true);
  198. vkms_obj->pages = NULL;
  199. out:
  200. mutex_unlock(&vkms_obj->pages_lock);
  201. return ret;
  202. }