4
4
*/
5
5
6
6
#include "gem/i915_gem_ioctls.h"
7
+ #include "gem/i915_gem_lmem.h"
7
8
#include "gem/i915_gem_region.h"
8
9
9
10
#include "i915_drv.h"
10
11
#include "i915_trace.h"
11
12
#include "i915_user_extensions.h"
12
13
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
+
13
52
static int i915_gem_publish (struct drm_i915_gem_object * obj ,
14
53
struct drm_file * file ,
15
54
u64 * size_p ,
@@ -29,14 +68,12 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
29
68
}
30
69
31
70
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 )
35
72
{
73
+ struct intel_memory_region * mr = obj -> mm .placements [0 ];
36
74
int ret ;
37
75
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 ));
40
77
if (size == 0 )
41
78
return - EINVAL ;
42
79
@@ -62,6 +99,7 @@ i915_gem_dumb_create(struct drm_file *file,
62
99
struct drm_mode_create_dumb * args )
63
100
{
64
101
struct drm_i915_gem_object * obj ;
102
+ struct intel_memory_region * mr ;
65
103
enum intel_memory_type mem_type ;
66
104
int cpp = DIV_ROUND_UP (args -> bpp , 8 );
67
105
u32 format ;
@@ -102,10 +140,10 @@ i915_gem_dumb_create(struct drm_file *file,
102
140
if (!obj )
103
141
return - ENOMEM ;
104
142
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 );
109
147
if (ret )
110
148
goto object_free ;
111
149
@@ -129,6 +167,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
129
167
struct drm_i915_private * i915 = to_i915 (dev );
130
168
struct drm_i915_gem_create * args = data ;
131
169
struct drm_i915_gem_object * obj ;
170
+ struct intel_memory_region * mr ;
132
171
int ret ;
133
172
134
173
i915_gem_flush_free_objects (i915 );
@@ -137,10 +176,10 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
137
176
if (!obj )
138
177
return - ENOMEM ;
139
178
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 );
144
183
if (ret )
145
184
goto object_free ;
146
185
@@ -156,7 +195,144 @@ struct create_ext {
156
195
struct drm_i915_gem_object * vanilla_object ;
157
196
};
158
197
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
+
159
334
static 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,
172
348
struct drm_i915_private * i915 = to_i915 (dev );
173
349
struct drm_i915_gem_create_ext * args = data ;
174
350
struct create_ext ext_data = { .i915 = i915 };
351
+ struct intel_memory_region * * placements_ext ;
175
352
struct drm_i915_gem_object * obj ;
176
353
int ret ;
177
354
@@ -189,19 +366,26 @@ i915_gem_create_ext_ioctl(struct drm_device *dev, void *data,
189
366
create_extensions ,
190
367
ARRAY_SIZE (create_extensions ),
191
368
& ext_data );
369
+ placements_ext = obj -> mm .placements ;
192
370
if (ret )
193
371
goto object_free ;
194
372
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 );
199
381
if (ret )
200
382
goto object_free ;
201
383
202
384
return i915_gem_publish (obj , file , & args -> size , & args -> handle );
203
385
204
386
object_free :
387
+ if (obj -> mm .n_placements > 1 )
388
+ kfree (placements_ext );
205
389
i915_gem_object_free (obj );
206
390
return ret ;
207
391
}
0 commit comments