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 	struct intel_memory_region *mem = obj->mm.region;
26 	struct list_head *blocks = &obj->mm.blocks;
27 	resource_size_t size = obj->base.size;
28 	resource_size_t prev_end;
29 	struct i915_buddy_block *block;
30 	unsigned int flags;
31 	struct sg_table *st;
32 	struct scatterlist *sg;
33 	unsigned int sg_page_sizes;
34 	int ret;
35 
36 	st = kmalloc(sizeof(*st), GFP_KERNEL);
37 	if (!st)
38 		return -ENOMEM;
39 
40 	if (sg_alloc_table(st, size >> ilog2(mem->mm.chunk_size), GFP_KERNEL)) {
41 		kfree(st);
42 		return -ENOMEM;
43 	}
44 
45 	flags = I915_ALLOC_MIN_PAGE_SIZE;
46 	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
47 		flags |= I915_ALLOC_CONTIGUOUS;
48 
49 	ret = __intel_memory_region_get_pages_buddy(mem, size, flags, blocks);
50 	if (ret)
51 		goto err_free_sg;
52 
53 	GEM_BUG_ON(list_empty(blocks));
54 
55 	sg = st->sgl;
56 	st->nents = 0;
57 	sg_page_sizes = 0;
58 	prev_end = (resource_size_t)-1;
59 
60 	list_for_each_entry(block, blocks, link) {
61 		u64 block_size, offset;
62 
63 		block_size = min_t(u64, size,
64 				   i915_buddy_block_size(&mem->mm, block));
65 		offset = i915_buddy_block_offset(block);
66 
67 		GEM_BUG_ON(overflows_type(block_size, sg->length));
68 
69 		if (offset != prev_end ||
70 		    add_overflows_t(typeof(sg->length), sg->length, block_size)) {
71 			if (st->nents) {
72 				sg_page_sizes |= sg->length;
73 				sg = __sg_next(sg);
74 			}
75 
76 			sg_dma_address(sg) = mem->region.start + offset;
77 			sg_dma_len(sg) = block_size;
78 
79 			sg->length = block_size;
80 
81 			st->nents++;
82 		} else {
83 			sg->length += block_size;
84 			sg_dma_len(sg) += block_size;
85 		}
86 
87 		prev_end = offset + block_size;
88 	};
89 
90 	sg_page_sizes |= sg->length;
91 	sg_mark_end(sg);
92 	i915_sg_trim(st);
93 
94 	__i915_gem_object_set_pages(obj, st, sg_page_sizes);
95 
96 	return 0;
97 
98 err_free_sg:
99 	sg_free_table(st);
100 	kfree(st);
101 	return ret;
102 }
103 
104 void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
105 					struct intel_memory_region *mem,
106 					unsigned long flags)
107 {
108 	INIT_LIST_HEAD(&obj->mm.blocks);
109 	obj->mm.region = intel_memory_region_get(mem);
110 	obj->flags |= flags;
111 
112 	mutex_lock(&mem->objects.lock);
113 
114 	if (obj->flags & I915_BO_ALLOC_VOLATILE)
115 		list_add(&obj->mm.region_link, &mem->objects.purgeable);
116 	else
117 		list_add(&obj->mm.region_link, &mem->objects.list);
118 
119 	mutex_unlock(&mem->objects.lock);
120 }
121 
122 void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj)
123 {
124 	struct intel_memory_region *mem = obj->mm.region;
125 
126 	mutex_lock(&mem->objects.lock);
127 	list_del(&obj->mm.region_link);
128 	mutex_unlock(&mem->objects.lock);
129 
130 	intel_memory_region_put(mem);
131 }
132 
133 struct drm_i915_gem_object *
134 i915_gem_object_create_region(struct intel_memory_region *mem,
135 			      resource_size_t size,
136 			      unsigned int flags)
137 {
138 	struct drm_i915_gem_object *obj;
139 
140 	/*
141 	 * NB: Our use of resource_size_t for the size stems from using struct
142 	 * resource for the mem->region. We might need to revisit this in the
143 	 * future.
144 	 */
145 
146 	GEM_BUG_ON(flags & ~I915_BO_ALLOC_FLAGS);
147 
148 	if (!mem)
149 		return ERR_PTR(-ENODEV);
150 
151 	size = round_up(size, mem->min_page_size);
152 
153 	GEM_BUG_ON(!size);
154 	GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_MIN_ALIGNMENT));
155 
156 	/*
157 	 * XXX: There is a prevalence of the assumption that we fit the
158 	 * object's page count inside a 32bit _signed_ variable. Let's document
159 	 * this and catch if we ever need to fix it. In the meantime, if you do
160 	 * spot such a local variable, please consider fixing!
161 	 */
162 
163 	if (size >> PAGE_SHIFT > INT_MAX)
164 		return ERR_PTR(-E2BIG);
165 
166 	if (overflows_type(size, obj->base.size))
167 		return ERR_PTR(-E2BIG);
168 
169 	obj = mem->ops->create_object(mem, size, flags);
170 	if (!IS_ERR(obj))
171 		trace_i915_gem_object_create(obj);
172 
173 	return obj;
174 }
175