i915_gem_phys.c (5871B)
1/* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2014-2016 Intel Corporation 5 */ 6 7#include <linux/highmem.h> 8#include <linux/shmem_fs.h> 9#include <linux/swap.h> 10 11#include <drm/drm_cache.h> 12 13#include "gt/intel_gt.h" 14#include "i915_drv.h" 15#include "i915_gem_object.h" 16#include "i915_gem_region.h" 17#include "i915_gem_tiling.h" 18#include "i915_scatterlist.h" 19 20static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) 21{ 22 struct address_space *mapping = obj->base.filp->f_mapping; 23 struct drm_i915_private *i915 = to_i915(obj->base.dev); 24 struct scatterlist *sg; 25 struct sg_table *st; 26 dma_addr_t dma; 27 void *vaddr; 28 void *dst; 29 int i; 30 31 if (GEM_WARN_ON(i915_gem_object_needs_bit17_swizzle(obj))) 32 return -EINVAL; 33 34 /* 35 * Always aligning to the object size, allows a single allocation 36 * to handle all possible callers, and given typical object sizes, 37 * the alignment of the buddy allocation will naturally match. 38 */ 39 vaddr = dma_alloc_coherent(obj->base.dev->dev, 40 roundup_pow_of_two(obj->base.size), 41 &dma, GFP_KERNEL); 42 if (!vaddr) 43 return -ENOMEM; 44 45 st = kmalloc(sizeof(*st), GFP_KERNEL); 46 if (!st) 47 goto err_pci; 48 49 if (sg_alloc_table(st, 1, GFP_KERNEL)) 50 goto err_st; 51 52 sg = st->sgl; 53 sg->offset = 0; 54 sg->length = obj->base.size; 55 56 sg_assign_page(sg, (struct page *)vaddr); 57 sg_dma_address(sg) = dma; 58 sg_dma_len(sg) = obj->base.size; 59 60 dst = vaddr; 61 for (i = 0; i < obj->base.size / PAGE_SIZE; i++) { 62 struct page *page; 63 void *src; 64 65 page = shmem_read_mapping_page(mapping, i); 66 if (IS_ERR(page)) 67 goto err_st; 68 69 src = kmap_atomic(page); 70 memcpy(dst, src, PAGE_SIZE); 71 drm_clflush_virt_range(dst, PAGE_SIZE); 72 kunmap_atomic(src); 73 74 put_page(page); 75 dst += PAGE_SIZE; 76 } 77 78 intel_gt_chipset_flush(to_gt(i915)); 79 80 /* We're no longer struct page backed */ 81 obj->mem_flags &= ~I915_BO_FLAG_STRUCT_PAGE; 82 __i915_gem_object_set_pages(obj, st, sg->length); 83 84 return 0; 85 86err_st: 87 kfree(st); 88err_pci: 89 dma_free_coherent(obj->base.dev->dev, 90 roundup_pow_of_two(obj->base.size), 91 vaddr, dma); 92 return -ENOMEM; 93} 94 95void 96i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, 97 struct sg_table *pages) 98{ 99 dma_addr_t dma = sg_dma_address(pages->sgl); 100 void *vaddr = sg_page(pages->sgl); 101 102 __i915_gem_object_release_shmem(obj, pages, false); 103 104 if (obj->mm.dirty) { 105 struct address_space *mapping = obj->base.filp->f_mapping; 106 void *src = vaddr; 107 int i; 108 109 for (i = 0; i < obj->base.size / PAGE_SIZE; i++) { 110 struct page *page; 111 char *dst; 112 113 page = shmem_read_mapping_page(mapping, i); 114 if (IS_ERR(page)) 115 continue; 116 117 dst = kmap_atomic(page); 118 drm_clflush_virt_range(src, PAGE_SIZE); 119 memcpy(dst, src, PAGE_SIZE); 120 kunmap_atomic(dst); 121 122 set_page_dirty(page); 123 if (obj->mm.madv == I915_MADV_WILLNEED) 124 mark_page_accessed(page); 125 put_page(page); 126 127 src += PAGE_SIZE; 128 } 129 obj->mm.dirty = false; 130 } 131 132 sg_free_table(pages); 133 kfree(pages); 134 135 dma_free_coherent(obj->base.dev->dev, 136 roundup_pow_of_two(obj->base.size), 137 vaddr, dma); 138} 139 140int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj, 141 const struct drm_i915_gem_pwrite *args) 142{ 143 void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset; 144 char __user *user_data = u64_to_user_ptr(args->data_ptr); 145 struct drm_i915_private *i915 = to_i915(obj->base.dev); 146 int err; 147 148 err = i915_gem_object_wait(obj, 149 I915_WAIT_INTERRUPTIBLE | 150 I915_WAIT_ALL, 151 MAX_SCHEDULE_TIMEOUT); 152 if (err) 153 return err; 154 155 /* 156 * We manually control the domain here and pretend that it 157 * remains coherent i.e. in the GTT domain, like shmem_pwrite. 158 */ 159 i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU); 160 161 if (copy_from_user(vaddr, user_data, args->size)) 162 return -EFAULT; 163 164 drm_clflush_virt_range(vaddr, args->size); 165 intel_gt_chipset_flush(to_gt(i915)); 166 167 i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU); 168 return 0; 169} 170 171int i915_gem_object_pread_phys(struct drm_i915_gem_object *obj, 172 const struct drm_i915_gem_pread *args) 173{ 174 void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset; 175 char __user *user_data = u64_to_user_ptr(args->data_ptr); 176 int err; 177 178 err = i915_gem_object_wait(obj, 179 I915_WAIT_INTERRUPTIBLE, 180 MAX_SCHEDULE_TIMEOUT); 181 if (err) 182 return err; 183 184 drm_clflush_virt_range(vaddr, args->size); 185 if (copy_to_user(user_data, vaddr, args->size)) 186 return -EFAULT; 187 188 return 0; 189} 190 191static int i915_gem_object_shmem_to_phys(struct drm_i915_gem_object *obj) 192{ 193 struct sg_table *pages; 194 int err; 195 196 pages = __i915_gem_object_unset_pages(obj); 197 198 err = i915_gem_object_get_pages_phys(obj); 199 if (err) 200 goto err_xfer; 201 202 /* Perma-pin (until release) the physical set of pages */ 203 __i915_gem_object_pin_pages(obj); 204 205 if (!IS_ERR_OR_NULL(pages)) 206 i915_gem_object_put_pages_shmem(obj, pages); 207 208 i915_gem_object_release_memory_region(obj); 209 return 0; 210 211err_xfer: 212 if (!IS_ERR_OR_NULL(pages)) { 213 unsigned int sg_page_sizes = i915_sg_dma_sizes(pages->sgl); 214 215 __i915_gem_object_set_pages(obj, pages, sg_page_sizes); 216 } 217 return err; 218} 219 220int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) 221{ 222 int err; 223 224 assert_object_held(obj); 225 226 if (align > obj->base.size) 227 return -EINVAL; 228 229 if (!i915_gem_object_is_shmem(obj)) 230 return -EINVAL; 231 232 if (!i915_gem_object_has_struct_page(obj)) 233 return 0; 234 235 err = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE); 236 if (err) 237 return err; 238 239 if (obj->mm.madv != I915_MADV_WILLNEED) 240 return -EFAULT; 241 242 if (i915_gem_object_has_tiling_quirk(obj)) 243 return -EFAULT; 244 245 if (obj->mm.mapping || i915_gem_object_has_pinned_pages(obj)) 246 return -EBUSY; 247 248 if (unlikely(obj->mm.madv != I915_MADV_WILLNEED)) { 249 drm_dbg(obj->base.dev, 250 "Attempting to obtain a purgeable object\n"); 251 return -EFAULT; 252 } 253 254 return i915_gem_object_shmem_to_phys(obj); 255} 256 257#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 258#include "selftests/i915_gem_phys.c" 259#endif