• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
i915_gem_object_put_pages_buddy(struct drm_i915_gem_object * obj,struct sg_table * pages)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
i915_gem_object_get_pages_buddy(struct drm_i915_gem_object * obj)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 
i915_gem_object_init_memory_region(struct drm_i915_gem_object * obj,struct intel_memory_region * mem,unsigned long flags)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 
111 	obj->flags |= flags;
112 	if (obj->base.size <= mem->min_page_size)
113 		obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
114 
115 	mutex_lock(&mem->objects.lock);
116 
117 	if (obj->flags & I915_BO_ALLOC_VOLATILE)
118 		list_add(&obj->mm.region_link, &mem->objects.purgeable);
119 	else
120 		list_add(&obj->mm.region_link, &mem->objects.list);
121 
122 	mutex_unlock(&mem->objects.lock);
123 }
124 
i915_gem_object_release_memory_region(struct drm_i915_gem_object * obj)125 void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj)
126 {
127 	struct intel_memory_region *mem = obj->mm.region;
128 
129 	mutex_lock(&mem->objects.lock);
130 	list_del(&obj->mm.region_link);
131 	mutex_unlock(&mem->objects.lock);
132 
133 	intel_memory_region_put(mem);
134 }
135 
136 struct drm_i915_gem_object *
i915_gem_object_create_region(struct intel_memory_region * mem,resource_size_t size,unsigned int flags)137 i915_gem_object_create_region(struct intel_memory_region *mem,
138 			      resource_size_t size,
139 			      unsigned int flags)
140 {
141 	struct drm_i915_gem_object *obj;
142 
143 	/*
144 	 * NB: Our use of resource_size_t for the size stems from using struct
145 	 * resource for the mem->region. We might need to revisit this in the
146 	 * future.
147 	 */
148 
149 	GEM_BUG_ON(flags & ~I915_BO_ALLOC_FLAGS);
150 
151 	if (!mem)
152 		return ERR_PTR(-ENODEV);
153 
154 	size = round_up(size, mem->min_page_size);
155 
156 	GEM_BUG_ON(!size);
157 	GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_MIN_ALIGNMENT));
158 
159 	/*
160 	 * XXX: There is a prevalence of the assumption that we fit the
161 	 * object's page count inside a 32bit _signed_ variable. Let's document
162 	 * this and catch if we ever need to fix it. In the meantime, if you do
163 	 * spot such a local variable, please consider fixing!
164 	 */
165 
166 	if (size >> PAGE_SHIFT > INT_MAX)
167 		return ERR_PTR(-E2BIG);
168 
169 	if (overflows_type(size, obj->base.size))
170 		return ERR_PTR(-E2BIG);
171 
172 	obj = mem->ops->create_object(mem, size, flags);
173 	if (!IS_ERR(obj))
174 		trace_i915_gem_object_create(obj);
175 
176 	return obj;
177 }
178