0001
0002
0003
0004
0005
0006 #include <linux/iosys-map.h>
0007 #include <linux/mm.h>
0008 #include <linux/pagemap.h>
0009 #include <linux/shmem_fs.h>
0010
0011 #include "gem/i915_gem_object.h"
0012 #include "gem/i915_gem_lmem.h"
0013 #include "shmem_utils.h"
0014
0015 struct file *shmem_create_from_data(const char *name, void *data, size_t len)
0016 {
0017 struct file *file;
0018 int err;
0019
0020 file = shmem_file_setup(name, PAGE_ALIGN(len), VM_NORESERVE);
0021 if (IS_ERR(file))
0022 return file;
0023
0024 err = shmem_write(file, 0, data, len);
0025 if (err) {
0026 fput(file);
0027 return ERR_PTR(err);
0028 }
0029
0030 return file;
0031 }
0032
0033 struct file *shmem_create_from_object(struct drm_i915_gem_object *obj)
0034 {
0035 struct file *file;
0036 void *ptr;
0037
0038 if (i915_gem_object_is_shmem(obj)) {
0039 file = obj->base.filp;
0040 atomic_long_inc(&file->f_count);
0041 return file;
0042 }
0043
0044 ptr = i915_gem_object_pin_map_unlocked(obj, i915_gem_object_is_lmem(obj) ?
0045 I915_MAP_WC : I915_MAP_WB);
0046 if (IS_ERR(ptr))
0047 return ERR_CAST(ptr);
0048
0049 file = shmem_create_from_data("", ptr, obj->base.size);
0050 i915_gem_object_unpin_map(obj);
0051
0052 return file;
0053 }
0054
0055 void *shmem_pin_map(struct file *file)
0056 {
0057 struct page **pages;
0058 size_t n_pages, i;
0059 void *vaddr;
0060
0061 n_pages = file->f_mapping->host->i_size >> PAGE_SHIFT;
0062 pages = kvmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL);
0063 if (!pages)
0064 return NULL;
0065
0066 for (i = 0; i < n_pages; i++) {
0067 pages[i] = shmem_read_mapping_page_gfp(file->f_mapping, i,
0068 GFP_KERNEL);
0069 if (IS_ERR(pages[i]))
0070 goto err_page;
0071 }
0072
0073 vaddr = vmap(pages, n_pages, VM_MAP_PUT_PAGES, PAGE_KERNEL);
0074 if (!vaddr)
0075 goto err_page;
0076 mapping_set_unevictable(file->f_mapping);
0077 return vaddr;
0078 err_page:
0079 while (i--)
0080 put_page(pages[i]);
0081 kvfree(pages);
0082 return NULL;
0083 }
0084
0085 void shmem_unpin_map(struct file *file, void *ptr)
0086 {
0087 mapping_clear_unevictable(file->f_mapping);
0088 vfree(ptr);
0089 }
0090
0091 static int __shmem_rw(struct file *file, loff_t off,
0092 void *ptr, size_t len,
0093 bool write)
0094 {
0095 unsigned long pfn;
0096
0097 for (pfn = off >> PAGE_SHIFT; len; pfn++) {
0098 unsigned int this =
0099 min_t(size_t, PAGE_SIZE - offset_in_page(off), len);
0100 struct page *page;
0101 void *vaddr;
0102
0103 page = shmem_read_mapping_page_gfp(file->f_mapping, pfn,
0104 GFP_KERNEL);
0105 if (IS_ERR(page))
0106 return PTR_ERR(page);
0107
0108 vaddr = kmap(page);
0109 if (write) {
0110 memcpy(vaddr + offset_in_page(off), ptr, this);
0111 set_page_dirty(page);
0112 } else {
0113 memcpy(ptr, vaddr + offset_in_page(off), this);
0114 }
0115 mark_page_accessed(page);
0116 kunmap(page);
0117 put_page(page);
0118
0119 len -= this;
0120 ptr += this;
0121 off = 0;
0122 }
0123
0124 return 0;
0125 }
0126
0127 int shmem_read_to_iosys_map(struct file *file, loff_t off,
0128 struct iosys_map *map, size_t map_off, size_t len)
0129 {
0130 unsigned long pfn;
0131
0132 for (pfn = off >> PAGE_SHIFT; len; pfn++) {
0133 unsigned int this =
0134 min_t(size_t, PAGE_SIZE - offset_in_page(off), len);
0135 struct page *page;
0136 void *vaddr;
0137
0138 page = shmem_read_mapping_page_gfp(file->f_mapping, pfn,
0139 GFP_KERNEL);
0140 if (IS_ERR(page))
0141 return PTR_ERR(page);
0142
0143 vaddr = kmap(page);
0144 iosys_map_memcpy_to(map, map_off, vaddr + offset_in_page(off),
0145 this);
0146 mark_page_accessed(page);
0147 kunmap(page);
0148 put_page(page);
0149
0150 len -= this;
0151 map_off += this;
0152 off = 0;
0153 }
0154
0155 return 0;
0156 }
0157
0158 int shmem_read(struct file *file, loff_t off, void *dst, size_t len)
0159 {
0160 return __shmem_rw(file, off, dst, len, false);
0161 }
0162
0163 int shmem_write(struct file *file, loff_t off, void *src, size_t len)
0164 {
0165 return __shmem_rw(file, off, src, len, true);
0166 }
0167
0168 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
0169 #include "st_shmem_utils.c"
0170 #endif