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
44 */
55
66 #include "gem/i915_gem_ioctls.h"
7+#include "gem/i915_gem_lmem.h"
78 #include "gem/i915_gem_region.h"
89
910 #include "i915_drv.h"
1011 #include "i915_trace.h"
1112 #include "i915_user_extensions.h"
1213
14+static 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+
30+static 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+
1352 static int i915_gem_publish(struct drm_i915_gem_object *obj,
1453 struct drm_file *file,
1554 u64 *size_p,
@@ -29,14 +68,12 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj, · 13 unmodified lines
2968 }
3069
3170 static int
32−i915_gem_setup(struct drm_i915_gem_object *obj,
33− struct intel_memory_region *mr,
34− u64 size)
71+i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
3572 {
73+ struct intel_memory_region *mr = obj->mm.placements[0];
3674 int ret;
3775
38− GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
39− size = round_up(size, mr->min_page_size);
76+ size = round_up(size, object_max_page_size(obj));
4077 if (size == 0)
4178 return -EINVAL;
4279
@@ -62,6 +99,7 @@ i915_gem_dumb_create(struct drm_file *file, · 19 unmodified lines
6299 struct drm_mode_create_dumb *args)
63100 {
64101 struct drm_i915_gem_object *obj;
102+ struct intel_memory_region *mr;
65103 enum intel_memory_type mem_type;
66104 int cpp = DIV_ROUND_UP(args->bpp, 8);
67105 u32 format;
@@ -102,10 +140,10 @@ i915_gem_dumb_create(struct drm_file *file, · 34 unmodified lines
102140 if (!obj)
103141 return -ENOMEM;
104142
105− ret = i915_gem_setup(obj,
106− intel_memory_region_by_type(to_i915(dev),
107− mem_type),
108− args->size);
143+ mr = intel_memory_region_by_type(to_i915(dev), mem_type);
144+ object_set_placements(obj, &mr, 1);
145+
146+ ret = i915_gem_setup(obj, args->size);
109147 if (ret)
110148 goto object_free;
111149
@@ -129,6 +167,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, · 17 unmodified lines
129167 struct drm_i915_private *i915 = to_i915(dev);
130168 struct drm_i915_gem_create *args = data;
131169 struct drm_i915_gem_object *obj;
170+ struct intel_memory_region *mr;
132171 int ret;
133172
134173 i915_gem_flush_free_objects(i915);
@@ -137,10 +176,10 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, · 2 unmodified lines
137176 if (!obj)
138177 return -ENOMEM;
139178
140− ret = i915_gem_setup(obj,
141− intel_memory_region_by_type(i915,
142− INTEL_MEMORY_SYSTEM),
143− args->size);
179+ mr = intel_memory_region_by_type(i915, INTEL_MEMORY_SYSTEM);
180+ object_set_placements(obj, &mr, 1);
181+
182+ ret = i915_gem_setup(obj, args->size);
144183 if (ret)
145184 goto object_free;
146185
@@ -156,7 +195,144 @@ struct create_ext { · 9 unmodified lines
156195 struct drm_i915_gem_object *vanilla_object;
157196 };
158197
198+static 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+
220+static 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+
300+out_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+
318+out_free:
319+ kfree(placements);
320+ return ret;
321+}
322+
323+static 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+
159334 static const i915_user_extension_fn create_extensions[] = {
335+ [I915_GEM_CREATE_EXT_MEMORY_REGIONS] = ext_set_placements,
160336 };
161337
162338 /**
@@ -172,6 +348,7 @@ i915_gem_create_ext_ioctl(struct drm_device *dev, void *data, · 9 unmodified lines
172348 struct drm_i915_private *i915 = to_i915(dev);
173349 struct drm_i915_gem_create_ext *args = data;
174350 struct create_ext ext_data = { .i915 = i915 };
351+ struct intel_memory_region **placements_ext;
175352 struct drm_i915_gem_object *obj;
176353 int ret;
177354
@@ -189,19 +366,26 @@ i915_gem_create_ext_ioctl(struct drm_device *dev, void *data, · 11 unmodified lines
189366 create_extensions,
190367 ARRAY_SIZE(create_extensions),
191368 &ext_data);
369+ placements_ext = obj->mm.placements;
192370 if (ret)
193371 goto object_free;
194372
195− ret = i915_gem_setup(obj,
196− intel_memory_region_by_type(i915,
197− INTEL_MEMORY_SYSTEM),
198− args->size);
373+ if (!placements_ext) {
374+ struct intel_memory_region *mr =
375+ intel_memory_region_by_type(i915, INTEL_MEMORY_SYSTEM);
376+
377+ object_set_placements(obj, &mr, 1);
378+ }
379+
380+ ret = i915_gem_setup(obj, args->size);
199381 if (ret)
200382 goto object_free;
201383
202384 return i915_gem_publish(obj, file, &args->size, &args->handle);
203385
204386 object_free:
387+ if (obj->mm.n_placements > 1)
388+ kfree(placements_ext);
205389 i915_gem_object_free(obj);
206390 return ret;
207391 }
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
249249 if (obj->ops->release)
250250 obj->ops->release(obj);
251251
252+ if (obj->mm.n_placements > 1)
253+ kfree(obj->mm.placements);
254+
252255 /* But keep the pointer alive for RCU-protected lookups */
253256 call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
254257 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
219219 atomic_t pages_pin_count;
220220 atomic_t shrink_pin;
221221
222+ /**
223+ * Priority list of potential placements for this object.
224+ */
225+ struct intel_memory_region **placements;
226+ int n_placements;
227+
222228 /**
223229 * Memory region for this object.
224230 */
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
842842 return true;
843843 }
844844
845+static 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+
845863 #define expand32(x) (((x) << 0) | ((x) << 8) | ((x) << 16) | ((x) << 24))
846864 static int __igt_mmap(struct drm_i915_private *i915,
847865 struct drm_i915_gem_object *obj,
@@ -950,6 +968,8 @@ static int igt_mmap(void *arg) · 102 unmodified lines
950968 if (IS_ERR(obj))
951969 return PTR_ERR(obj);
952970
971+ object_set_placements(obj, &mr, 1);
972+
953973 err = __igt_mmap(i915, obj, I915_MMAP_TYPE_GTT);
954974 if (err == 0)
955975 err = __igt_mmap(i915, obj, I915_MMAP_TYPE_WC);
@@ -1068,6 +1088,8 @@ static int igt_mmap_access(void *arg) · 112 unmodified lines
10681088 if (IS_ERR(obj))
10691089 return PTR_ERR(obj);
10701090
1091+ object_set_placements(obj, &mr, 1);
1092+
10711093 err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_GTT);
10721094 if (err == 0)
10731095 err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_WB);
@@ -1211,6 +1233,8 @@ static int igt_mmap_gpu(void *arg) · 137 unmodified lines
12111233 if (IS_ERR(obj))
12121234 return PTR_ERR(obj);
12131235
1236+ object_set_placements(obj, &mr, 1);
1237+
12141238 err = __igt_mmap_gpu(i915, obj, I915_MMAP_TYPE_GTT);
12151239 if (err == 0)
12161240 err = __igt_mmap_gpu(i915, obj, I915_MMAP_TYPE_WC);
@@ -1354,6 +1378,8 @@ static int igt_mmap_revoke(void *arg) · 137 unmodified lines
13541378 if (IS_ERR(obj))
13551379 return PTR_ERR(obj);
13561380
1381+ object_set_placements(obj, &mr, 1);
1382+
13571383 err = __igt_mmap_revoke(i915, obj, I915_MMAP_TYPE_GTT);
13581384 if (err == 0)
13591385 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
2828 },
2929 };
3030
31+struct intel_memory_region *
32+intel_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+
3147 struct intel_memory_region *
3248 intel_memory_region_by_type(struct drm_i915_private *i915,
3349 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
9797 } objects;
9898 };
9999
100+struct intel_memory_region *
101+intel_memory_region_lookup(struct drm_i915_private *i915,
102+ u16 class, u16 instance);
103+
100104 int intel_memory_region_init_buddy(struct intel_memory_region *mem);
101105 void intel_memory_region_release_buddy(struct intel_memory_region *mem);
102106
include/uapi/drm/i915_drm.h+62−0
@@ -2616,6 +2616,11 @@ struct drm_i915_gem_create_ext { · 2615 unmodified lines
26162616 *
26172617 * The (page-aligned) allocated size for the object will be returned.
26182618 *
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.
26192624 */
26202625 __u64 size;
26212626 /**
@@ -2636,10 +2641,67 @@ struct drm_i915_gem_create_ext { · 14 unmodified lines
26362641 * If we don't supply any extensions then we get the same old gem_create
26372642 * behaviour.
26382643 *
2644+ * For I915_GEM_CREATE_EXT_MEMORY_REGIONS usage see
2645+ * struct drm_i915_gem_create_ext_memory_regions.
26392646 */
2647+#define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0
26402648 __u64 extensions;
26412649 };
26422650
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+ */
2689+struct 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+
26432705 #if defined(__cplusplus)
26442706 }
26452707 #endif