History

drm/i915/uapi: implement object placement extension

Add new extension to support setting an immutable-priority-list of potential placements, at creation time. If we use the normal gem_create or gem_create_ext without the extensions/placements then we still get the old behaviour with only placing the object in system memory. v2(Daniel & Jason): - Add a bunch of kernel-doc - Simplify design for placements extension

Matthew Auld committed 5 years ago

Commit 2459e561 parent ebcb4027 files · +318 −17Browse files

Unified · Split

7 files
  1. drivers/gpu/drm/i915/gem/i915_gem_create.c +201 −17
  2. drivers/gpu/drm/i915/gem/i915_gem_object.c +3 −0
  3. drivers/gpu/drm/i915/gem/i915_gem_object_types.h +6 −0
  4. drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +26 −0
  5. drivers/gpu/drm/i915/intel_memory_region.c +16 −0
  6. drivers/gpu/drm/i915/intel_memory_region.h +4 −0
  7. include/uapi/drm/i915_drm.h +62 −0
drivers/gpu/drm/i915/gem/i915_gem_create.c+201−17
@@ -4,12 +4,51 @@ · 3 unmodified lines
4 */4 */
5 5
6#include "gem/i915_gem_ioctls.h"6#include "gem/i915_gem_ioctls.h"
7#include "gem/i915_gem_lmem.h"
7#include "gem/i915_gem_region.h"8#include "gem/i915_gem_region.h"
8 9
9#include "i915_drv.h"10#include "i915_drv.h"
10#include "i915_trace.h"11#include "i915_trace.h"
11#include "i915_user_extensions.h"12#include "i915_user_extensions.h"
12 13
14static u32 object_max_page_size(struct drm_i915_gem_object *obj)
15{
16 u32 max_page_size = 0;
17 int i;
18
19 for (i = 0; i < obj->mm.n_placements; i++) {
20 struct intel_memory_region *mr = obj->mm.placements[i];
21
22 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
23 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
24 }
25
26 GEM_BUG_ON(!max_page_size);
27 return max_page_size;
28}
29
30static void object_set_placements(struct drm_i915_gem_object *obj,
31 struct intel_memory_region **placements,
32 unsigned int n_placements)
33{
34 GEM_BUG_ON(!n_placements);
35
36 /*
37 * For the common case of one memory region, skip storing an
38 * allocated array and just point at the region directly.
39 */
40 if (n_placements == 1) {
41 struct intel_memory_region *mr = placements[0];
42 struct drm_i915_private *i915 = mr->i915;
43
44 obj->mm.placements = &i915->mm.regions[mr->id];
45 obj->mm.n_placements = 1;
46 } else {
47 obj->mm.placements = placements;
48 obj->mm.n_placements = n_placements;
49 }
50}
51
13static int i915_gem_publish(struct drm_i915_gem_object *obj,52static int i915_gem_publish(struct drm_i915_gem_object *obj,
14 struct drm_file *file,53 struct drm_file *file,
15 u64 *size_p,54 u64 *size_p,
@@ -29,14 +68,12 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj, · 13 unmodified lines
29}68}
30 69
31static int70static int
32i915_gem_setup(struct drm_i915_gem_object *obj,71i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
33 struct intel_memory_region *mr,
34 u64 size)
35{72{
73 struct intel_memory_region *mr = obj->mm.placements[0];
36 int ret;74 int ret;
37 75
38 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));76 size = round_up(size, object_max_page_size(obj));
39 size = round_up(size, mr->min_page_size);
40 if (size == 0)77 if (size == 0)
41 return -EINVAL;78 return -EINVAL;
42 79
@@ -62,6 +99,7 @@ i915_gem_dumb_create(struct drm_file *file, · 19 unmodified lines
62 struct drm_mode_create_dumb *args)99 struct drm_mode_create_dumb *args)
63{100{
64 struct drm_i915_gem_object *obj;101 struct drm_i915_gem_object *obj;
102 struct intel_memory_region *mr;
65 enum intel_memory_type mem_type;103 enum intel_memory_type mem_type;
66 int cpp = DIV_ROUND_UP(args->bpp, 8);104 int cpp = DIV_ROUND_UP(args->bpp, 8);
67 u32 format;105 u32 format;
@@ -102,10 +140,10 @@ i915_gem_dumb_create(struct drm_file *file, · 34 unmodified lines
102 if (!obj)140 if (!obj)
103 return -ENOMEM;141 return -ENOMEM;
104 142
105 ret = i915_gem_setup(obj,143 mr = intel_memory_region_by_type(to_i915(dev), mem_type);
106 intel_memory_region_by_type(to_i915(dev),144 object_set_placements(obj, &mr, 1);
107 mem_type),145
108 args->size);146 ret = i915_gem_setup(obj, args->size);
109 if (ret)147 if (ret)
110 goto object_free;148 goto object_free;
111 149
@@ -129,6 +167,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, · 17 unmodified lines
129 struct drm_i915_private *i915 = to_i915(dev);167 struct drm_i915_private *i915 = to_i915(dev);
130 struct drm_i915_gem_create *args = data;168 struct drm_i915_gem_create *args = data;
131 struct drm_i915_gem_object *obj;169 struct drm_i915_gem_object *obj;
170 struct intel_memory_region *mr;
132 int ret;171 int ret;
133 172
134 i915_gem_flush_free_objects(i915);173 i915_gem_flush_free_objects(i915);
@@ -137,10 +176,10 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, · 2 unmodified lines
137 if (!obj)176 if (!obj)
138 return -ENOMEM;177 return -ENOMEM;
139 178
140 ret = i915_gem_setup(obj,179 mr = intel_memory_region_by_type(i915, INTEL_MEMORY_SYSTEM);
141 intel_memory_region_by_type(i915,180 object_set_placements(obj, &mr, 1);
142 INTEL_MEMORY_SYSTEM),181
143 args->size);182 ret = i915_gem_setup(obj, args->size);
144 if (ret)183 if (ret)
145 goto object_free;184 goto object_free;
146 185
@@ -156,7 +195,144 @@ struct create_ext { · 9 unmodified lines
156 struct drm_i915_gem_object *vanilla_object;195 struct drm_i915_gem_object *vanilla_object;
157};196};
158 197
198static void repr_placements(char *buf, size_t size,
199 struct intel_memory_region **placements,
200 int n_placements)
201{
202 int i;
203
204 buf[0] = '\0';
205
206 for (i = 0; i < n_placements; i++) {
207 struct intel_memory_region *mr = placements[i];
208 int r;
209
210 r = snprintf(buf, size, "\n %s -> { class: %d, inst: %d }",
211 mr->name, mr->type, mr->instance);
212 if (r >= size)
213 return;
214
215 buf += r;
216 size -= r;
217 }
218}
219
220static int set_placements(struct drm_i915_gem_create_ext_memory_regions *args,
221 struct create_ext *ext_data)
222{
223 struct drm_i915_private *i915 = ext_data->i915;
224 struct drm_i915_gem_memory_class_instance __user *uregions =
225 u64_to_user_ptr(args->regions);
226 struct drm_i915_gem_object *obj = ext_data->vanilla_object;
227 struct intel_memory_region **placements;
228 u32 mask;
229 int i, ret = 0;
230
231 if (args->pad) {
232 drm_dbg(&i915->drm, "pad should be zero\n");
233 ret = -EINVAL;
234 }
235
236 if (!args->num_regions) {
237 drm_dbg(&i915->drm, "num_regions is zero\n");
238 ret = -EINVAL;
239 }
240
241 if (args->num_regions > ARRAY_SIZE(i915->mm.regions)) {
242 drm_dbg(&i915->drm, "num_regions is too large\n");
243 ret = -EINVAL;
244 }
245
246 if (ret)
247 return ret;
248
249 placements = kmalloc_array(args->num_regions,
250 sizeof(struct intel_memory_region *),
251 GFP_KERNEL);
252 if (!placements)
253 return -ENOMEM;
254
255 mask = 0;
256 for (i = 0; i < args->num_regions; i++) {
257 struct drm_i915_gem_memory_class_instance region;
258 struct intel_memory_region *mr;
259
260 if (copy_from_user(&region, uregions, sizeof(region))) {
261 ret = -EFAULT;
262 goto out_free;
263 }
264
265 mr = intel_memory_region_lookup(i915,
266 region.memory_class,
267 region.memory_instance);
268 if (!mr || mr->private) {
269 drm_dbg(&i915->drm, "Device is missing region { class: %d, inst: %d } at index = %d\n",
270 region.memory_class, region.memory_instance, i);
271 ret = -EINVAL;
272 goto out_dump;
273 }
274
275 if (mask & BIT(mr->id)) {
276 drm_dbg(&i915->drm, "Found duplicate placement %s -> { class: %d, inst: %d } at index = %d\n",
277 mr->name, region.memory_class,
278 region.memory_instance, i);
279 ret = -EINVAL;
280 goto out_dump;
281 }
282
283 placements[i] = mr;
284 mask |= BIT(mr->id);
285
286 ++uregions;
287 }
288
289 if (obj->mm.placements) {
290 ret = -EINVAL;
291 goto out_dump;
292 }
293
294 object_set_placements(obj, placements, args->num_regions);
295 if (args->num_regions == 1)
296 kfree(placements);
297
298 return 0;
299
300out_dump:
301 if (1) {
302 char buf[256];
303
304 if (obj->mm.placements) {
305 repr_placements(buf,
306 sizeof(buf),
307 obj->mm.placements,
308 obj->mm.n_placements);
309 drm_dbg(&i915->drm,
310 "Placements were already set in previous EXT. Existing placements: %s\n",
311 buf);
312 }
313
314 repr_placements(buf, sizeof(buf), placements, i);
315 drm_dbg(&i915->drm, "New placements(so far validated): %s\n", buf);
316 }
317
318out_free:
319 kfree(placements);
320 return ret;
321}
322
323static int ext_set_placements(struct i915_user_extension __user *base,
324 void *data)
325{
326 struct drm_i915_gem_create_ext_memory_regions ext;
327
328 if (copy_from_user(&ext, base, sizeof(ext)))
329 return -EFAULT;
330
331 return set_placements(&ext, data);
332}
333
159static const i915_user_extension_fn create_extensions[] = {334static const i915_user_extension_fn create_extensions[] = {
335 [I915_GEM_CREATE_EXT_MEMORY_REGIONS] = ext_set_placements,
160};336};
161 337
162/**338/**
@@ -172,6 +348,7 @@ i915_gem_create_ext_ioctl(struct drm_device *dev, void *data, · 9 unmodified lines
172 struct drm_i915_private *i915 = to_i915(dev);348 struct drm_i915_private *i915 = to_i915(dev);
173 struct drm_i915_gem_create_ext *args = data;349 struct drm_i915_gem_create_ext *args = data;
174 struct create_ext ext_data = { .i915 = i915 };350 struct create_ext ext_data = { .i915 = i915 };
351 struct intel_memory_region **placements_ext;
175 struct drm_i915_gem_object *obj;352 struct drm_i915_gem_object *obj;
176 int ret;353 int ret;
177 354
@@ -189,19 +366,26 @@ i915_gem_create_ext_ioctl(struct drm_device *dev, void *data, · 11 unmodified lines
189 create_extensions,366 create_extensions,
190 ARRAY_SIZE(create_extensions),367 ARRAY_SIZE(create_extensions),
191 &ext_data);368 &ext_data);
369 placements_ext = obj->mm.placements;
192 if (ret)370 if (ret)
193 goto object_free;371 goto object_free;
194 372
195 ret = i915_gem_setup(obj,373 if (!placements_ext) {
196 intel_memory_region_by_type(i915,374 struct intel_memory_region *mr =
197 INTEL_MEMORY_SYSTEM),375 intel_memory_region_by_type(i915, INTEL_MEMORY_SYSTEM);
198 args->size);376
377 object_set_placements(obj, &mr, 1);
378 }
379
380 ret = i915_gem_setup(obj, args->size);
199 if (ret)381 if (ret)
200 goto object_free;382 goto object_free;
201 383
202 return i915_gem_publish(obj, file, &args->size, &args->handle);384 return i915_gem_publish(obj, file, &args->size, &args->handle);
203 385
204object_free:386object_free:
387 if (obj->mm.n_placements > 1)
388 kfree(placements_ext);
205 i915_gem_object_free(obj);389 i915_gem_object_free(obj);
206 return ret;390 return ret;
207}391}
drivers/gpu/drm/i915/gem/i915_gem_object.c+3−0
@@ -249,6 +249,9 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915, · 248 unmodified lines
249 if (obj->ops->release)249 if (obj->ops->release)
250 obj->ops->release(obj);250 obj->ops->release(obj);
251 251
252 if (obj->mm.n_placements > 1)
253 kfree(obj->mm.placements);
254
252 /* But keep the pointer alive for RCU-protected lookups */255 /* But keep the pointer alive for RCU-protected lookups */
253 call_rcu(&obj->rcu, __i915_gem_free_object_rcu);256 call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
254 cond_resched();257 cond_resched();
drivers/gpu/drm/i915/gem/i915_gem_object_types.h+6−0
@@ -219,6 +219,12 @@ struct drm_i915_gem_object { · 218 unmodified lines
219 atomic_t pages_pin_count;219 atomic_t pages_pin_count;
220 atomic_t shrink_pin;220 atomic_t shrink_pin;
221 221
222 /**
223 * Priority list of potential placements for this object.
224 */
225 struct intel_memory_region **placements;
226 int n_placements;
227
222 /**228 /**
223 * Memory region for this object.229 * Memory region for this object.
224 */230 */
drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c+26−0
@@ -842,6 +842,24 @@ static bool can_mmap(struct drm_i915_gem_object *obj, enum i915_mmap_type type) · 841 unmodified lines
842 return true;842 return true;
843}843}
844 844
845static void object_set_placements(struct drm_i915_gem_object *obj,
846 struct intel_memory_region **placements,
847 unsigned int n_placements)
848{
849 GEM_BUG_ON(!n_placements);
850
851 if (n_placements == 1) {
852 struct drm_i915_private *i915 = to_i915(obj->base.dev);
853 struct intel_memory_region *mr = placements[0];
854
855 obj->mm.placements = &i915->mm.regions[mr->id];
856 obj->mm.n_placements = 1;
857 } else {
858 obj->mm.placements = placements;
859 obj->mm.n_placements = n_placements;
860 }
861}
862
845#define expand32(x) (((x) << 0) | ((x) << 8) | ((x) << 16) | ((x) << 24))863#define expand32(x) (((x) << 0) | ((x) << 8) | ((x) << 16) | ((x) << 24))
846static int __igt_mmap(struct drm_i915_private *i915,864static int __igt_mmap(struct drm_i915_private *i915,
847 struct drm_i915_gem_object *obj,865 struct drm_i915_gem_object *obj,
@@ -950,6 +968,8 @@ static int igt_mmap(void *arg) · 102 unmodified lines
950 if (IS_ERR(obj))968 if (IS_ERR(obj))
951 return PTR_ERR(obj);969 return PTR_ERR(obj);
952 970
971 object_set_placements(obj, &mr, 1);
972
953 err = __igt_mmap(i915, obj, I915_MMAP_TYPE_GTT);973 err = __igt_mmap(i915, obj, I915_MMAP_TYPE_GTT);
954 if (err == 0)974 if (err == 0)
955 err = __igt_mmap(i915, obj, I915_MMAP_TYPE_WC);975 err = __igt_mmap(i915, obj, I915_MMAP_TYPE_WC);
@@ -1068,6 +1088,8 @@ static int igt_mmap_access(void *arg) · 112 unmodified lines
1068 if (IS_ERR(obj))1088 if (IS_ERR(obj))
1069 return PTR_ERR(obj);1089 return PTR_ERR(obj);
1070 1090
1091 object_set_placements(obj, &mr, 1);
1092
1071 err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_GTT);1093 err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_GTT);
1072 if (err == 0)1094 if (err == 0)
1073 err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_WB);1095 err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_WB);
@@ -1211,6 +1233,8 @@ static int igt_mmap_gpu(void *arg) · 137 unmodified lines
1211 if (IS_ERR(obj))1233 if (IS_ERR(obj))
1212 return PTR_ERR(obj);1234 return PTR_ERR(obj);
1213 1235
1236 object_set_placements(obj, &mr, 1);
1237
1214 err = __igt_mmap_gpu(i915, obj, I915_MMAP_TYPE_GTT);1238 err = __igt_mmap_gpu(i915, obj, I915_MMAP_TYPE_GTT);
1215 if (err == 0)1239 if (err == 0)
1216 err = __igt_mmap_gpu(i915, obj, I915_MMAP_TYPE_WC);1240 err = __igt_mmap_gpu(i915, obj, I915_MMAP_TYPE_WC);
@@ -1354,6 +1378,8 @@ static int igt_mmap_revoke(void *arg) · 137 unmodified lines
1354 if (IS_ERR(obj))1378 if (IS_ERR(obj))
1355 return PTR_ERR(obj);1379 return PTR_ERR(obj);
1356 1380
1381 object_set_placements(obj, &mr, 1);
1382
1357 err = __igt_mmap_revoke(i915, obj, I915_MMAP_TYPE_GTT);1383 err = __igt_mmap_revoke(i915, obj, I915_MMAP_TYPE_GTT);
1358 if (err == 0)1384 if (err == 0)
1359 err = __igt_mmap_revoke(i915, obj, I915_MMAP_TYPE_WC);1385 err = __igt_mmap_revoke(i915, obj, I915_MMAP_TYPE_WC);
drivers/gpu/drm/i915/intel_memory_region.c+16−0
@@ -28,6 +28,22 @@ static const struct { · 27 unmodified lines
28 },28 },
29};29};
30 30
31struct intel_memory_region *
32intel_memory_region_lookup(struct drm_i915_private *i915,
33 u16 class, u16 instance)
34{
35 struct intel_memory_region *mr;
36 int id;
37
38 /* XXX: consider maybe converting to an rb tree at some point */
39 for_each_memory_region(mr, i915, id) {
40 if (mr->type == class && mr->instance == instance)
41 return mr;
42 }
43
44 return NULL;
45}
46
31struct intel_memory_region *47struct intel_memory_region *
32intel_memory_region_by_type(struct drm_i915_private *i915,48intel_memory_region_by_type(struct drm_i915_private *i915,
33 enum intel_memory_type mem_type)49 enum intel_memory_type mem_type)
drivers/gpu/drm/i915/intel_memory_region.h+4−0
@@ -97,6 +97,10 @@ struct intel_memory_region { · 96 unmodified lines
97 } objects;97 } objects;
98};98};
99 99
100struct intel_memory_region *
101intel_memory_region_lookup(struct drm_i915_private *i915,
102 u16 class, u16 instance);
103
100int intel_memory_region_init_buddy(struct intel_memory_region *mem);104int intel_memory_region_init_buddy(struct intel_memory_region *mem);
101void intel_memory_region_release_buddy(struct intel_memory_region *mem);105void intel_memory_region_release_buddy(struct intel_memory_region *mem);
102 106
include/uapi/drm/i915_drm.h+62−0
@@ -2616,6 +2616,11 @@ struct drm_i915_gem_create_ext { · 2615 unmodified lines
2616 *2616 *
2617 * The (page-aligned) allocated size for the object will be returned.2617 * The (page-aligned) allocated size for the object will be returned.
2618 *2618 *
2619 * Note that for some devices we have might have further minimum
2620 * page-size restrictions(larger than 4K), like for device local-memory.
2621 * However in general the final size here should always reflect any
2622 * rounding up, if for example using the I915_GEM_CREATE_EXT_MEMORY_REGIONS
2623 * extension to place the object in device local-memory.
2619 */2624 */
2620 __u64 size;2625 __u64 size;
2621 /**2626 /**
@@ -2636,10 +2641,67 @@ struct drm_i915_gem_create_ext { · 14 unmodified lines
2636 * If we don't supply any extensions then we get the same old gem_create2641 * If we don't supply any extensions then we get the same old gem_create
2637 * behaviour.2642 * behaviour.
2638 *2643 *
2644 * For I915_GEM_CREATE_EXT_MEMORY_REGIONS usage see
2645 * struct drm_i915_gem_create_ext_memory_regions.
2639 */2646 */
2647#define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0
2640 __u64 extensions;2648 __u64 extensions;
2641};2649};
2642 2650
2651/**
2652 * struct drm_i915_gem_create_ext_memory_regions - The
2653 * I915_GEM_CREATE_EXT_MEMORY_REGIONS extension.
2654 *
2655 * Set the object with the desired set of placements/regions in priority
2656 * order. Each entry must be unique and supported by the device.
2657 *
2658 * This is provided as an array of struct drm_i915_gem_memory_class_instance, or
2659 * an equivalent layout of class:instance pair encodings. See struct
2660 * drm_i915_query_memory_regions and DRM_I915_QUERY_MEMORY_REGIONS for how to
2661 * query the supported regions for a device.
2662 *
2663 * As an example, on discrete devices, if we wish to set the placement as
2664 * device local-memory we can do something like:
2665 *
2666 * .. code-block:: C
2667 *
2668 * struct drm_i915_gem_memory_class_instance region_lmem = {
2669 * .memory_class = I915_MEMORY_CLASS_DEVICE,
2670 * .memory_instance = 0,
2671 * };
2672 * struct drm_i915_gem_create_ext_memory_regions regions = {
2673 * .base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS },
2674 * .regions = (uintptr_t)&region_lmem,
2675 * .num_regions = 1,
2676 * };
2677 * struct drm_i915_gem_create_ext create_ext = {
2678 * .size = 16 * PAGE_SIZE,
2679 * .extensions = (uintptr_t)&regions,
2680 * };
2681 *
2682 * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext);
2683 * if (err) ...
2684 *
2685 * At which point we get the object handle in &drm_i915_gem_create_ext.handle,
2686 * along with the final object size in &drm_i915_gem_create_ext.size, which
2687 * should account for any rounding up, if required.
2688 */
2689struct drm_i915_gem_create_ext_memory_regions {
2690 /** @base: Extension link. See struct i915_user_extension. */
2691 struct i915_user_extension base;
2692
2693 /** @pad: MBZ */
2694 __u32 pad;
2695 /** @num_regions: Number of elements in the @regions array. */
2696 __u32 num_regions;
2697 /**
2698 * @regions: The regions/placements array.
2699 *
2700 * An array of struct drm_i915_gem_memory_class_instance.
2701 */
2702 __u64 regions;
2703};
2704
2643#if defined(__cplusplus)2705#if defined(__cplusplus)
2644}2706}
2645#endif2707#endif