1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2019 Intel Corporation 4 */ 5 6 #include "intel_memory_region.h" 7 #include "i915_gem_region.h" 8 #include "i915_drv.h" 9 #include "i915_trace.h" 10 11 void 12 i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj, 13 struct sg_table *pages) 14 { 15 __intel_memory_region_put_pages_buddy(obj->mm.region, &obj->mm.blocks); 16 17 obj->mm.dirty = false; 18 sg_free_table(pages); 19 kfree(pages); 20 } 21 22 int 23 i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj) 24 { 25 const u64 max_segment = i915_sg_segment_size(); 26 struct intel_memory_region *mem = obj->mm.region; 27 struct list_head *blocks = &obj->mm.blocks; 28 resource_size_t size = obj->base.size; 29 resource_size_t prev_end; 30 struct i915_buddy_block *block; 31 unsigned int flags; 32 struct sg_table *st; 33 struct scatterlist *sg; 34 unsigned int sg_page_sizes; 35 int ret; 36 37 st = kmalloc(sizeof(*st), GFP_KERNEL); 38 if (!st) 39 return -ENOMEM; 40 41 if (sg_alloc_table(st, size >> PAGE_SHIFT, GFP_KERNEL)) { 42 kfree(st); 43 return -ENOMEM; 44 } 45 46 flags = I915_ALLOC_MIN_PAGE_SIZE; 47 if (obj->flags & I915_BO_ALLOC_CONTIGUOUS) 48 flags |= I915_ALLOC_CONTIGUOUS; 49 50 ret = __intel_memory_region_get_pages_buddy(mem, size, flags, blocks); 51 if (ret) 52 goto err_free_sg; 53 54 GEM_BUG_ON(list_empty(blocks)); 55 56 sg = st->sgl; 57 st->nents = 0; 58 sg_page_sizes = 0; 59 prev_end = (resource_size_t)-1; 60 61 list_for_each_entry(block, blocks, link) { 62 u64 block_size, offset; 63 64 block_size = min_t(u64, size, 65 i915_buddy_block_size(&mem->mm, block)); 66 offset = i915_buddy_block_offset(block); 67 68 while (block_size) { 69 u64 len; 70 71 if (offset != prev_end || sg->length >= max_segment) { 72 if (st->nents) { 73 sg_page_sizes |= sg->length; 74 sg = __sg_next(sg); 75 } 76 77 sg_dma_address(sg) = mem->region.start + offset; 78 sg_dma_len(sg) = 0; 79 sg->length = 0; 80 st->nents++; 81 } 82 83 len = min(block_size, max_segment - sg->length); 84 sg->length += len; 85 sg_dma_len(sg) += len; 86 87 offset += len; 88 block_size -= len; 89 90 prev_end = offset; 91 } 92 } 93 94 sg_page_sizes |= sg->length; 95 sg_mark_end(sg); 96 i915_sg_trim(st); 97 98 __i915_gem_object_set_pages(obj, st, sg_page_sizes); 99 100 return 0; 101 102 err_free_sg: 103 sg_free_table(st); 104 kfree(st); 105 return ret; 106 } 107 108 void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj, 109 struct intel_memory_region *mem) 110 { 111 INIT_LIST_HEAD(&obj->mm.blocks); 112 obj->mm.region = intel_memory_region_get(mem); 113 114 if (obj->base.size <= mem->min_page_size) 115 obj->flags |= I915_BO_ALLOC_CONTIGUOUS; 116 117 mutex_lock(&mem->objects.lock); 118 119 if (obj->flags & I915_BO_ALLOC_VOLATILE) 120 list_add(&obj->mm.region_link, &mem->objects.purgeable); 121 else 122 list_add(&obj->mm.region_link, &mem->objects.list); 123 124 mutex_unlock(&mem->objects.lock); 125 } 126 127 void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj) 128 { 129 struct intel_memory_region *mem = obj->mm.region; 130 131 mutex_lock(&mem->objects.lock); 132 list_del(&obj->mm.region_link); 133 mutex_unlock(&mem->objects.lock); 134 135 intel_memory_region_put(mem); 136 } 137 138 struct drm_i915_gem_object * 139 i915_gem_object_create_region(struct intel_memory_region *mem, 140 resource_size_t size, 141 unsigned int flags) 142 { 143 struct drm_i915_gem_object *obj; 144 int err; 145 146 /* 147 * NB: Our use of resource_size_t for the size stems from using struct 148 * resource for the mem->region. We might need to revisit this in the 149 * future. 150 */ 151 152 GEM_BUG_ON(flags & ~I915_BO_ALLOC_FLAGS); 153 154 if (!mem) 155 return ERR_PTR(-ENODEV); 156 157 size = round_up(size, mem->min_page_size); 158 159 GEM_BUG_ON(!size); 160 GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_MIN_ALIGNMENT)); 161 162 if (i915_gem_object_size_2big(size)) 163 return ERR_PTR(-E2BIG); 164 165 obj = i915_gem_object_alloc(); 166 if (!obj) 167 return ERR_PTR(-ENOMEM); 168 169 err = mem->ops->init_object(mem, obj, size, flags); 170 if (err) 171 goto err_object_free; 172 173 trace_i915_gem_object_create(obj); 174 return obj; 175 176 err_object_free: 177 i915_gem_object_free(obj); 178 return ERR_PTR(err); 179 } 180