diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 898 |
1 files changed, 730 insertions, 168 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 37427e4016cb..b52cba0f16d2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -43,8 +43,8 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, | |||
43 | uint64_t offset, | 43 | uint64_t offset, |
44 | uint64_t size); | 44 | uint64_t size); |
45 | static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj); | 45 | static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj); |
46 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); | 46 | static int i915_gem_object_get_pages(struct drm_gem_object *obj); |
47 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); | 47 | static void i915_gem_object_put_pages(struct drm_gem_object *obj); |
48 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); | 48 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); |
49 | static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, | 49 | static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, |
50 | unsigned alignment); | 50 | unsigned alignment); |
@@ -136,6 +136,224 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, | |||
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | static inline int | ||
140 | fast_shmem_read(struct page **pages, | ||
141 | loff_t page_base, int page_offset, | ||
142 | char __user *data, | ||
143 | int length) | ||
144 | { | ||
145 | char __iomem *vaddr; | ||
146 | int ret; | ||
147 | |||
148 | vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0); | ||
149 | if (vaddr == NULL) | ||
150 | return -ENOMEM; | ||
151 | ret = __copy_to_user_inatomic(data, vaddr + page_offset, length); | ||
152 | kunmap_atomic(vaddr, KM_USER0); | ||
153 | |||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | static inline int | ||
158 | slow_shmem_copy(struct page *dst_page, | ||
159 | int dst_offset, | ||
160 | struct page *src_page, | ||
161 | int src_offset, | ||
162 | int length) | ||
163 | { | ||
164 | char *dst_vaddr, *src_vaddr; | ||
165 | |||
166 | dst_vaddr = kmap_atomic(dst_page, KM_USER0); | ||
167 | if (dst_vaddr == NULL) | ||
168 | return -ENOMEM; | ||
169 | |||
170 | src_vaddr = kmap_atomic(src_page, KM_USER1); | ||
171 | if (src_vaddr == NULL) { | ||
172 | kunmap_atomic(dst_vaddr, KM_USER0); | ||
173 | return -ENOMEM; | ||
174 | } | ||
175 | |||
176 | memcpy(dst_vaddr + dst_offset, src_vaddr + src_offset, length); | ||
177 | |||
178 | kunmap_atomic(src_vaddr, KM_USER1); | ||
179 | kunmap_atomic(dst_vaddr, KM_USER0); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * This is the fast shmem pread path, which attempts to copy_from_user directly | ||
186 | * from the backing pages of the object to the user's address space. On a | ||
187 | * fault, it fails so we can fall back to i915_gem_shmem_pwrite_slow(). | ||
188 | */ | ||
189 | static int | ||
190 | i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, | ||
191 | struct drm_i915_gem_pread *args, | ||
192 | struct drm_file *file_priv) | ||
193 | { | ||
194 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
195 | ssize_t remain; | ||
196 | loff_t offset, page_base; | ||
197 | char __user *user_data; | ||
198 | int page_offset, page_length; | ||
199 | int ret; | ||
200 | |||
201 | user_data = (char __user *) (uintptr_t) args->data_ptr; | ||
202 | remain = args->size; | ||
203 | |||
204 | mutex_lock(&dev->struct_mutex); | ||
205 | |||
206 | ret = i915_gem_object_get_pages(obj); | ||
207 | if (ret != 0) | ||
208 | goto fail_unlock; | ||
209 | |||
210 | ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset, | ||
211 | args->size); | ||
212 | if (ret != 0) | ||
213 | goto fail_put_pages; | ||
214 | |||
215 | obj_priv = obj->driver_private; | ||
216 | offset = args->offset; | ||
217 | |||
218 | while (remain > 0) { | ||
219 | /* Operation in this page | ||
220 | * | ||
221 | * page_base = page offset within aperture | ||
222 | * page_offset = offset within page | ||
223 | * page_length = bytes to copy for this page | ||
224 | */ | ||
225 | page_base = (offset & ~(PAGE_SIZE-1)); | ||
226 | page_offset = offset & (PAGE_SIZE-1); | ||
227 | page_length = remain; | ||
228 | if ((page_offset + remain) > PAGE_SIZE) | ||
229 | page_length = PAGE_SIZE - page_offset; | ||
230 | |||
231 | ret = fast_shmem_read(obj_priv->pages, | ||
232 | page_base, page_offset, | ||
233 | user_data, page_length); | ||
234 | if (ret) | ||
235 | goto fail_put_pages; | ||
236 | |||
237 | remain -= page_length; | ||
238 | user_data += page_length; | ||
239 | offset += page_length; | ||
240 | } | ||
241 | |||
242 | fail_put_pages: | ||
243 | i915_gem_object_put_pages(obj); | ||
244 | fail_unlock: | ||
245 | mutex_unlock(&dev->struct_mutex); | ||
246 | |||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * This is the fallback shmem pread path, which allocates temporary storage | ||
252 | * in kernel space to copy_to_user into outside of the struct_mutex, so we | ||
253 | * can copy out of the object's backing pages while holding the struct mutex | ||
254 | * and not take page faults. | ||
255 | */ | ||
256 | static int | ||
257 | i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, | ||
258 | struct drm_i915_gem_pread *args, | ||
259 | struct drm_file *file_priv) | ||
260 | { | ||
261 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
262 | struct mm_struct *mm = current->mm; | ||
263 | struct page **user_pages; | ||
264 | ssize_t remain; | ||
265 | loff_t offset, pinned_pages, i; | ||
266 | loff_t first_data_page, last_data_page, num_pages; | ||
267 | int shmem_page_index, shmem_page_offset; | ||
268 | int data_page_index, data_page_offset; | ||
269 | int page_length; | ||
270 | int ret; | ||
271 | uint64_t data_ptr = args->data_ptr; | ||
272 | |||
273 | remain = args->size; | ||
274 | |||
275 | /* Pin the user pages containing the data. We can't fault while | ||
276 | * holding the struct mutex, yet we want to hold it while | ||
277 | * dereferencing the user data. | ||
278 | */ | ||
279 | first_data_page = data_ptr / PAGE_SIZE; | ||
280 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | ||
281 | num_pages = last_data_page - first_data_page + 1; | ||
282 | |||
283 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | ||
284 | if (user_pages == NULL) | ||
285 | return -ENOMEM; | ||
286 | |||
287 | down_read(&mm->mmap_sem); | ||
288 | pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, | ||
289 | num_pages, 0, 0, user_pages, NULL); | ||
290 | up_read(&mm->mmap_sem); | ||
291 | if (pinned_pages < num_pages) { | ||
292 | ret = -EFAULT; | ||
293 | goto fail_put_user_pages; | ||
294 | } | ||
295 | |||
296 | mutex_lock(&dev->struct_mutex); | ||
297 | |||
298 | ret = i915_gem_object_get_pages(obj); | ||
299 | if (ret != 0) | ||
300 | goto fail_unlock; | ||
301 | |||
302 | ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset, | ||
303 | args->size); | ||
304 | if (ret != 0) | ||
305 | goto fail_put_pages; | ||
306 | |||
307 | obj_priv = obj->driver_private; | ||
308 | offset = args->offset; | ||
309 | |||
310 | while (remain > 0) { | ||
311 | /* Operation in this page | ||
312 | * | ||
313 | * shmem_page_index = page number within shmem file | ||
314 | * shmem_page_offset = offset within page in shmem file | ||
315 | * data_page_index = page number in get_user_pages return | ||
316 | * data_page_offset = offset with data_page_index page. | ||
317 | * page_length = bytes to copy for this page | ||
318 | */ | ||
319 | shmem_page_index = offset / PAGE_SIZE; | ||
320 | shmem_page_offset = offset & ~PAGE_MASK; | ||
321 | data_page_index = data_ptr / PAGE_SIZE - first_data_page; | ||
322 | data_page_offset = data_ptr & ~PAGE_MASK; | ||
323 | |||
324 | page_length = remain; | ||
325 | if ((shmem_page_offset + page_length) > PAGE_SIZE) | ||
326 | page_length = PAGE_SIZE - shmem_page_offset; | ||
327 | if ((data_page_offset + page_length) > PAGE_SIZE) | ||
328 | page_length = PAGE_SIZE - data_page_offset; | ||
329 | |||
330 | ret = slow_shmem_copy(user_pages[data_page_index], | ||
331 | data_page_offset, | ||
332 | obj_priv->pages[shmem_page_index], | ||
333 | shmem_page_offset, | ||
334 | page_length); | ||
335 | if (ret) | ||
336 | goto fail_put_pages; | ||
337 | |||
338 | remain -= page_length; | ||
339 | data_ptr += page_length; | ||
340 | offset += page_length; | ||
341 | } | ||
342 | |||
343 | fail_put_pages: | ||
344 | i915_gem_object_put_pages(obj); | ||
345 | fail_unlock: | ||
346 | mutex_unlock(&dev->struct_mutex); | ||
347 | fail_put_user_pages: | ||
348 | for (i = 0; i < pinned_pages; i++) { | ||
349 | SetPageDirty(user_pages[i]); | ||
350 | page_cache_release(user_pages[i]); | ||
351 | } | ||
352 | kfree(user_pages); | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
139 | /** | 357 | /** |
140 | * Reads data from the object referenced by handle. | 358 | * Reads data from the object referenced by handle. |
141 | * | 359 | * |
@@ -148,8 +366,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | |||
148 | struct drm_i915_gem_pread *args = data; | 366 | struct drm_i915_gem_pread *args = data; |
149 | struct drm_gem_object *obj; | 367 | struct drm_gem_object *obj; |
150 | struct drm_i915_gem_object *obj_priv; | 368 | struct drm_i915_gem_object *obj_priv; |
151 | ssize_t read; | ||
152 | loff_t offset; | ||
153 | int ret; | 369 | int ret; |
154 | 370 | ||
155 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 371 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); |
@@ -167,33 +383,13 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | |||
167 | return -EINVAL; | 383 | return -EINVAL; |
168 | } | 384 | } |
169 | 385 | ||
170 | mutex_lock(&dev->struct_mutex); | 386 | ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv); |
171 | 387 | if (ret != 0) | |
172 | ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset, | 388 | ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv); |
173 | args->size); | ||
174 | if (ret != 0) { | ||
175 | drm_gem_object_unreference(obj); | ||
176 | mutex_unlock(&dev->struct_mutex); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | offset = args->offset; | ||
181 | |||
182 | read = vfs_read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, | ||
183 | args->size, &offset); | ||
184 | if (read != args->size) { | ||
185 | drm_gem_object_unreference(obj); | ||
186 | mutex_unlock(&dev->struct_mutex); | ||
187 | if (read < 0) | ||
188 | return read; | ||
189 | else | ||
190 | return -EINVAL; | ||
191 | } | ||
192 | 389 | ||
193 | drm_gem_object_unreference(obj); | 390 | drm_gem_object_unreference(obj); |
194 | mutex_unlock(&dev->struct_mutex); | ||
195 | 391 | ||
196 | return 0; | 392 | return ret; |
197 | } | 393 | } |
198 | 394 | ||
199 | /* This is the fast write path which cannot handle | 395 | /* This is the fast write path which cannot handle |
@@ -223,29 +419,51 @@ fast_user_write(struct io_mapping *mapping, | |||
223 | */ | 419 | */ |
224 | 420 | ||
225 | static inline int | 421 | static inline int |
226 | slow_user_write(struct io_mapping *mapping, | 422 | slow_kernel_write(struct io_mapping *mapping, |
227 | loff_t page_base, int page_offset, | 423 | loff_t gtt_base, int gtt_offset, |
228 | char __user *user_data, | 424 | struct page *user_page, int user_offset, |
229 | int length) | 425 | int length) |
230 | { | 426 | { |
231 | char __iomem *vaddr; | 427 | char *src_vaddr, *dst_vaddr; |
232 | unsigned long unwritten; | 428 | unsigned long unwritten; |
233 | 429 | ||
234 | vaddr = io_mapping_map_wc(mapping, page_base); | 430 | dst_vaddr = io_mapping_map_atomic_wc(mapping, gtt_base); |
235 | if (vaddr == NULL) | 431 | src_vaddr = kmap_atomic(user_page, KM_USER1); |
236 | return -EFAULT; | 432 | unwritten = __copy_from_user_inatomic_nocache(dst_vaddr + gtt_offset, |
237 | unwritten = __copy_from_user(vaddr + page_offset, | 433 | src_vaddr + user_offset, |
238 | user_data, length); | 434 | length); |
239 | io_mapping_unmap(vaddr); | 435 | kunmap_atomic(src_vaddr, KM_USER1); |
436 | io_mapping_unmap_atomic(dst_vaddr); | ||
240 | if (unwritten) | 437 | if (unwritten) |
241 | return -EFAULT; | 438 | return -EFAULT; |
242 | return 0; | 439 | return 0; |
243 | } | 440 | } |
244 | 441 | ||
442 | static inline int | ||
443 | fast_shmem_write(struct page **pages, | ||
444 | loff_t page_base, int page_offset, | ||
445 | char __user *data, | ||
446 | int length) | ||
447 | { | ||
448 | char __iomem *vaddr; | ||
449 | |||
450 | vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0); | ||
451 | if (vaddr == NULL) | ||
452 | return -ENOMEM; | ||
453 | __copy_from_user_inatomic(vaddr + page_offset, data, length); | ||
454 | kunmap_atomic(vaddr, KM_USER0); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * This is the fast pwrite path, where we copy the data directly from the | ||
461 | * user into the GTT, uncached. | ||
462 | */ | ||
245 | static int | 463 | static int |
246 | i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | 464 | i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, |
247 | struct drm_i915_gem_pwrite *args, | 465 | struct drm_i915_gem_pwrite *args, |
248 | struct drm_file *file_priv) | 466 | struct drm_file *file_priv) |
249 | { | 467 | { |
250 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 468 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
251 | drm_i915_private_t *dev_priv = dev->dev_private; | 469 | drm_i915_private_t *dev_priv = dev->dev_private; |
@@ -273,7 +491,6 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | |||
273 | 491 | ||
274 | obj_priv = obj->driver_private; | 492 | obj_priv = obj->driver_private; |
275 | offset = obj_priv->gtt_offset + args->offset; | 493 | offset = obj_priv->gtt_offset + args->offset; |
276 | obj_priv->dirty = 1; | ||
277 | 494 | ||
278 | while (remain > 0) { | 495 | while (remain > 0) { |
279 | /* Operation in this page | 496 | /* Operation in this page |
@@ -292,16 +509,11 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | |||
292 | page_offset, user_data, page_length); | 509 | page_offset, user_data, page_length); |
293 | 510 | ||
294 | /* If we get a fault while copying data, then (presumably) our | 511 | /* If we get a fault while copying data, then (presumably) our |
295 | * source page isn't available. In this case, use the | 512 | * source page isn't available. Return the error and we'll |
296 | * non-atomic function | 513 | * retry in the slow path. |
297 | */ | 514 | */ |
298 | if (ret) { | 515 | if (ret) |
299 | ret = slow_user_write (dev_priv->mm.gtt_mapping, | 516 | goto fail; |
300 | page_base, page_offset, | ||
301 | user_data, page_length); | ||
302 | if (ret) | ||
303 | goto fail; | ||
304 | } | ||
305 | 517 | ||
306 | remain -= page_length; | 518 | remain -= page_length; |
307 | user_data += page_length; | 519 | user_data += page_length; |
@@ -315,39 +527,284 @@ fail: | |||
315 | return ret; | 527 | return ret; |
316 | } | 528 | } |
317 | 529 | ||
530 | /** | ||
531 | * This is the fallback GTT pwrite path, which uses get_user_pages to pin | ||
532 | * the memory and maps it using kmap_atomic for copying. | ||
533 | * | ||
534 | * This code resulted in x11perf -rgb10text consuming about 10% more CPU | ||
535 | * than using i915_gem_gtt_pwrite_fast on a G45 (32-bit). | ||
536 | */ | ||
318 | static int | 537 | static int |
319 | i915_gem_shmem_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | 538 | i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, |
320 | struct drm_i915_gem_pwrite *args, | 539 | struct drm_i915_gem_pwrite *args, |
321 | struct drm_file *file_priv) | 540 | struct drm_file *file_priv) |
322 | { | 541 | { |
542 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
543 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
544 | ssize_t remain; | ||
545 | loff_t gtt_page_base, offset; | ||
546 | loff_t first_data_page, last_data_page, num_pages; | ||
547 | loff_t pinned_pages, i; | ||
548 | struct page **user_pages; | ||
549 | struct mm_struct *mm = current->mm; | ||
550 | int gtt_page_offset, data_page_offset, data_page_index, page_length; | ||
323 | int ret; | 551 | int ret; |
324 | loff_t offset; | 552 | uint64_t data_ptr = args->data_ptr; |
325 | ssize_t written; | 553 | |
554 | remain = args->size; | ||
555 | |||
556 | /* Pin the user pages containing the data. We can't fault while | ||
557 | * holding the struct mutex, and all of the pwrite implementations | ||
558 | * want to hold it while dereferencing the user data. | ||
559 | */ | ||
560 | first_data_page = data_ptr / PAGE_SIZE; | ||
561 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | ||
562 | num_pages = last_data_page - first_data_page + 1; | ||
563 | |||
564 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | ||
565 | if (user_pages == NULL) | ||
566 | return -ENOMEM; | ||
567 | |||
568 | down_read(&mm->mmap_sem); | ||
569 | pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, | ||
570 | num_pages, 0, 0, user_pages, NULL); | ||
571 | up_read(&mm->mmap_sem); | ||
572 | if (pinned_pages < num_pages) { | ||
573 | ret = -EFAULT; | ||
574 | goto out_unpin_pages; | ||
575 | } | ||
326 | 576 | ||
327 | mutex_lock(&dev->struct_mutex); | 577 | mutex_lock(&dev->struct_mutex); |
578 | ret = i915_gem_object_pin(obj, 0); | ||
579 | if (ret) | ||
580 | goto out_unlock; | ||
581 | |||
582 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); | ||
583 | if (ret) | ||
584 | goto out_unpin_object; | ||
585 | |||
586 | obj_priv = obj->driver_private; | ||
587 | offset = obj_priv->gtt_offset + args->offset; | ||
588 | |||
589 | while (remain > 0) { | ||
590 | /* Operation in this page | ||
591 | * | ||
592 | * gtt_page_base = page offset within aperture | ||
593 | * gtt_page_offset = offset within page in aperture | ||
594 | * data_page_index = page number in get_user_pages return | ||
595 | * data_page_offset = offset with data_page_index page. | ||
596 | * page_length = bytes to copy for this page | ||
597 | */ | ||
598 | gtt_page_base = offset & PAGE_MASK; | ||
599 | gtt_page_offset = offset & ~PAGE_MASK; | ||
600 | data_page_index = data_ptr / PAGE_SIZE - first_data_page; | ||
601 | data_page_offset = data_ptr & ~PAGE_MASK; | ||
602 | |||
603 | page_length = remain; | ||
604 | if ((gtt_page_offset + page_length) > PAGE_SIZE) | ||
605 | page_length = PAGE_SIZE - gtt_page_offset; | ||
606 | if ((data_page_offset + page_length) > PAGE_SIZE) | ||
607 | page_length = PAGE_SIZE - data_page_offset; | ||
608 | |||
609 | ret = slow_kernel_write(dev_priv->mm.gtt_mapping, | ||
610 | gtt_page_base, gtt_page_offset, | ||
611 | user_pages[data_page_index], | ||
612 | data_page_offset, | ||
613 | page_length); | ||
614 | |||
615 | /* If we get a fault while copying data, then (presumably) our | ||
616 | * source page isn't available. Return the error and we'll | ||
617 | * retry in the slow path. | ||
618 | */ | ||
619 | if (ret) | ||
620 | goto out_unpin_object; | ||
621 | |||
622 | remain -= page_length; | ||
623 | offset += page_length; | ||
624 | data_ptr += page_length; | ||
625 | } | ||
626 | |||
627 | out_unpin_object: | ||
628 | i915_gem_object_unpin(obj); | ||
629 | out_unlock: | ||
630 | mutex_unlock(&dev->struct_mutex); | ||
631 | out_unpin_pages: | ||
632 | for (i = 0; i < pinned_pages; i++) | ||
633 | page_cache_release(user_pages[i]); | ||
634 | kfree(user_pages); | ||
635 | |||
636 | return ret; | ||
637 | } | ||
638 | |||
639 | /** | ||
640 | * This is the fast shmem pwrite path, which attempts to directly | ||
641 | * copy_from_user into the kmapped pages backing the object. | ||
642 | */ | ||
643 | static int | ||
644 | i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, | ||
645 | struct drm_i915_gem_pwrite *args, | ||
646 | struct drm_file *file_priv) | ||
647 | { | ||
648 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
649 | ssize_t remain; | ||
650 | loff_t offset, page_base; | ||
651 | char __user *user_data; | ||
652 | int page_offset, page_length; | ||
653 | int ret; | ||
654 | |||
655 | user_data = (char __user *) (uintptr_t) args->data_ptr; | ||
656 | remain = args->size; | ||
657 | |||
658 | mutex_lock(&dev->struct_mutex); | ||
659 | |||
660 | ret = i915_gem_object_get_pages(obj); | ||
661 | if (ret != 0) | ||
662 | goto fail_unlock; | ||
328 | 663 | ||
329 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); | 664 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); |
330 | if (ret) { | 665 | if (ret != 0) |
331 | mutex_unlock(&dev->struct_mutex); | 666 | goto fail_put_pages; |
332 | return ret; | 667 | |
668 | obj_priv = obj->driver_private; | ||
669 | offset = args->offset; | ||
670 | obj_priv->dirty = 1; | ||
671 | |||
672 | while (remain > 0) { | ||
673 | /* Operation in this page | ||
674 | * | ||
675 | * page_base = page offset within aperture | ||
676 | * page_offset = offset within page | ||
677 | * page_length = bytes to copy for this page | ||
678 | */ | ||
679 | page_base = (offset & ~(PAGE_SIZE-1)); | ||
680 | page_offset = offset & (PAGE_SIZE-1); | ||
681 | page_length = remain; | ||
682 | if ((page_offset + remain) > PAGE_SIZE) | ||
683 | page_length = PAGE_SIZE - page_offset; | ||
684 | |||
685 | ret = fast_shmem_write(obj_priv->pages, | ||
686 | page_base, page_offset, | ||
687 | user_data, page_length); | ||
688 | if (ret) | ||
689 | goto fail_put_pages; | ||
690 | |||
691 | remain -= page_length; | ||
692 | user_data += page_length; | ||
693 | offset += page_length; | ||
333 | } | 694 | } |
334 | 695 | ||
696 | fail_put_pages: | ||
697 | i915_gem_object_put_pages(obj); | ||
698 | fail_unlock: | ||
699 | mutex_unlock(&dev->struct_mutex); | ||
700 | |||
701 | return ret; | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * This is the fallback shmem pwrite path, which uses get_user_pages to pin | ||
706 | * the memory and maps it using kmap_atomic for copying. | ||
707 | * | ||
708 | * This avoids taking mmap_sem for faulting on the user's address while the | ||
709 | * struct_mutex is held. | ||
710 | */ | ||
711 | static int | ||
712 | i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | ||
713 | struct drm_i915_gem_pwrite *args, | ||
714 | struct drm_file *file_priv) | ||
715 | { | ||
716 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
717 | struct mm_struct *mm = current->mm; | ||
718 | struct page **user_pages; | ||
719 | ssize_t remain; | ||
720 | loff_t offset, pinned_pages, i; | ||
721 | loff_t first_data_page, last_data_page, num_pages; | ||
722 | int shmem_page_index, shmem_page_offset; | ||
723 | int data_page_index, data_page_offset; | ||
724 | int page_length; | ||
725 | int ret; | ||
726 | uint64_t data_ptr = args->data_ptr; | ||
727 | |||
728 | remain = args->size; | ||
729 | |||
730 | /* Pin the user pages containing the data. We can't fault while | ||
731 | * holding the struct mutex, and all of the pwrite implementations | ||
732 | * want to hold it while dereferencing the user data. | ||
733 | */ | ||
734 | first_data_page = data_ptr / PAGE_SIZE; | ||
735 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | ||
736 | num_pages = last_data_page - first_data_page + 1; | ||
737 | |||
738 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | ||
739 | if (user_pages == NULL) | ||
740 | return -ENOMEM; | ||
741 | |||
742 | down_read(&mm->mmap_sem); | ||
743 | pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, | ||
744 | num_pages, 0, 0, user_pages, NULL); | ||
745 | up_read(&mm->mmap_sem); | ||
746 | if (pinned_pages < num_pages) { | ||
747 | ret = -EFAULT; | ||
748 | goto fail_put_user_pages; | ||
749 | } | ||
750 | |||
751 | mutex_lock(&dev->struct_mutex); | ||
752 | |||
753 | ret = i915_gem_object_get_pages(obj); | ||
754 | if (ret != 0) | ||
755 | goto fail_unlock; | ||
756 | |||
757 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); | ||
758 | if (ret != 0) | ||
759 | goto fail_put_pages; | ||
760 | |||
761 | obj_priv = obj->driver_private; | ||
335 | offset = args->offset; | 762 | offset = args->offset; |
763 | obj_priv->dirty = 1; | ||
336 | 764 | ||
337 | written = vfs_write(obj->filp, | 765 | while (remain > 0) { |
338 | (char __user *)(uintptr_t) args->data_ptr, | 766 | /* Operation in this page |
339 | args->size, &offset); | 767 | * |
340 | if (written != args->size) { | 768 | * shmem_page_index = page number within shmem file |
341 | mutex_unlock(&dev->struct_mutex); | 769 | * shmem_page_offset = offset within page in shmem file |
342 | if (written < 0) | 770 | * data_page_index = page number in get_user_pages return |
343 | return written; | 771 | * data_page_offset = offset with data_page_index page. |
344 | else | 772 | * page_length = bytes to copy for this page |
345 | return -EINVAL; | 773 | */ |
774 | shmem_page_index = offset / PAGE_SIZE; | ||
775 | shmem_page_offset = offset & ~PAGE_MASK; | ||
776 | data_page_index = data_ptr / PAGE_SIZE - first_data_page; | ||
777 | data_page_offset = data_ptr & ~PAGE_MASK; | ||
778 | |||
779 | page_length = remain; | ||
780 | if ((shmem_page_offset + page_length) > PAGE_SIZE) | ||
781 | page_length = PAGE_SIZE - shmem_page_offset; | ||
782 | if ((data_page_offset + page_length) > PAGE_SIZE) | ||
783 | page_length = PAGE_SIZE - data_page_offset; | ||
784 | |||
785 | ret = slow_shmem_copy(obj_priv->pages[shmem_page_index], | ||
786 | shmem_page_offset, | ||
787 | user_pages[data_page_index], | ||
788 | data_page_offset, | ||
789 | page_length); | ||
790 | if (ret) | ||
791 | goto fail_put_pages; | ||
792 | |||
793 | remain -= page_length; | ||
794 | data_ptr += page_length; | ||
795 | offset += page_length; | ||
346 | } | 796 | } |
347 | 797 | ||
798 | fail_put_pages: | ||
799 | i915_gem_object_put_pages(obj); | ||
800 | fail_unlock: | ||
348 | mutex_unlock(&dev->struct_mutex); | 801 | mutex_unlock(&dev->struct_mutex); |
802 | fail_put_user_pages: | ||
803 | for (i = 0; i < pinned_pages; i++) | ||
804 | page_cache_release(user_pages[i]); | ||
805 | kfree(user_pages); | ||
349 | 806 | ||
350 | return 0; | 807 | return ret; |
351 | } | 808 | } |
352 | 809 | ||
353 | /** | 810 | /** |
@@ -388,10 +845,19 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
388 | if (obj_priv->phys_obj) | 845 | if (obj_priv->phys_obj) |
389 | ret = i915_gem_phys_pwrite(dev, obj, args, file_priv); | 846 | ret = i915_gem_phys_pwrite(dev, obj, args, file_priv); |
390 | else if (obj_priv->tiling_mode == I915_TILING_NONE && | 847 | else if (obj_priv->tiling_mode == I915_TILING_NONE && |
391 | dev->gtt_total != 0) | 848 | dev->gtt_total != 0) { |
392 | ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv); | 849 | ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv); |
393 | else | 850 | if (ret == -EFAULT) { |
394 | ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv); | 851 | ret = i915_gem_gtt_pwrite_slow(dev, obj, args, |
852 | file_priv); | ||
853 | } | ||
854 | } else { | ||
855 | ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file_priv); | ||
856 | if (ret == -EFAULT) { | ||
857 | ret = i915_gem_shmem_pwrite_slow(dev, obj, args, | ||
858 | file_priv); | ||
859 | } | ||
860 | } | ||
395 | 861 | ||
396 | #if WATCH_PWRITE | 862 | #if WATCH_PWRITE |
397 | if (ret) | 863 | if (ret) |
@@ -816,29 +1282,30 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, | |||
816 | } | 1282 | } |
817 | 1283 | ||
818 | static void | 1284 | static void |
819 | i915_gem_object_free_page_list(struct drm_gem_object *obj) | 1285 | i915_gem_object_put_pages(struct drm_gem_object *obj) |
820 | { | 1286 | { |
821 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1287 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
822 | int page_count = obj->size / PAGE_SIZE; | 1288 | int page_count = obj->size / PAGE_SIZE; |
823 | int i; | 1289 | int i; |
824 | 1290 | ||
825 | if (obj_priv->page_list == NULL) | 1291 | BUG_ON(obj_priv->pages_refcount == 0); |
826 | return; | ||
827 | 1292 | ||
1293 | if (--obj_priv->pages_refcount != 0) | ||
1294 | return; | ||
828 | 1295 | ||
829 | for (i = 0; i < page_count; i++) | 1296 | for (i = 0; i < page_count; i++) |
830 | if (obj_priv->page_list[i] != NULL) { | 1297 | if (obj_priv->pages[i] != NULL) { |
831 | if (obj_priv->dirty) | 1298 | if (obj_priv->dirty) |
832 | set_page_dirty(obj_priv->page_list[i]); | 1299 | set_page_dirty(obj_priv->pages[i]); |
833 | mark_page_accessed(obj_priv->page_list[i]); | 1300 | mark_page_accessed(obj_priv->pages[i]); |
834 | page_cache_release(obj_priv->page_list[i]); | 1301 | page_cache_release(obj_priv->pages[i]); |
835 | } | 1302 | } |
836 | obj_priv->dirty = 0; | 1303 | obj_priv->dirty = 0; |
837 | 1304 | ||
838 | drm_free(obj_priv->page_list, | 1305 | drm_free(obj_priv->pages, |
839 | page_count * sizeof(struct page *), | 1306 | page_count * sizeof(struct page *), |
840 | DRM_MEM_DRIVER); | 1307 | DRM_MEM_DRIVER); |
841 | obj_priv->page_list = NULL; | 1308 | obj_priv->pages = NULL; |
842 | } | 1309 | } |
843 | 1310 | ||
844 | static void | 1311 | static void |
@@ -1290,7 +1757,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
1290 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) | 1757 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) |
1291 | i915_gem_clear_fence_reg(obj); | 1758 | i915_gem_clear_fence_reg(obj); |
1292 | 1759 | ||
1293 | i915_gem_object_free_page_list(obj); | 1760 | i915_gem_object_put_pages(obj); |
1294 | 1761 | ||
1295 | if (obj_priv->gtt_space) { | 1762 | if (obj_priv->gtt_space) { |
1296 | atomic_dec(&dev->gtt_count); | 1763 | atomic_dec(&dev->gtt_count); |
@@ -1409,7 +1876,7 @@ i915_gem_evict_everything(struct drm_device *dev) | |||
1409 | } | 1876 | } |
1410 | 1877 | ||
1411 | static int | 1878 | static int |
1412 | i915_gem_object_get_page_list(struct drm_gem_object *obj) | 1879 | i915_gem_object_get_pages(struct drm_gem_object *obj) |
1413 | { | 1880 | { |
1414 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1881 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
1415 | int page_count, i; | 1882 | int page_count, i; |
@@ -1418,18 +1885,19 @@ i915_gem_object_get_page_list(struct drm_gem_object *obj) | |||
1418 | struct page *page; | 1885 | struct page *page; |
1419 | int ret; | 1886 | int ret; |
1420 | 1887 | ||
1421 | if (obj_priv->page_list) | 1888 | if (obj_priv->pages_refcount++ != 0) |
1422 | return 0; | 1889 | return 0; |
1423 | 1890 | ||
1424 | /* Get the list of pages out of our struct file. They'll be pinned | 1891 | /* Get the list of pages out of our struct file. They'll be pinned |
1425 | * at this point until we release them. | 1892 | * at this point until we release them. |
1426 | */ | 1893 | */ |
1427 | page_count = obj->size / PAGE_SIZE; | 1894 | page_count = obj->size / PAGE_SIZE; |
1428 | BUG_ON(obj_priv->page_list != NULL); | 1895 | BUG_ON(obj_priv->pages != NULL); |
1429 | obj_priv->page_list = drm_calloc(page_count, sizeof(struct page *), | 1896 | obj_priv->pages = drm_calloc(page_count, sizeof(struct page *), |
1430 | DRM_MEM_DRIVER); | 1897 | DRM_MEM_DRIVER); |
1431 | if (obj_priv->page_list == NULL) { | 1898 | if (obj_priv->pages == NULL) { |
1432 | DRM_ERROR("Faled to allocate page list\n"); | 1899 | DRM_ERROR("Faled to allocate page list\n"); |
1900 | obj_priv->pages_refcount--; | ||
1433 | return -ENOMEM; | 1901 | return -ENOMEM; |
1434 | } | 1902 | } |
1435 | 1903 | ||
@@ -1440,10 +1908,10 @@ i915_gem_object_get_page_list(struct drm_gem_object *obj) | |||
1440 | if (IS_ERR(page)) { | 1908 | if (IS_ERR(page)) { |
1441 | ret = PTR_ERR(page); | 1909 | ret = PTR_ERR(page); |
1442 | DRM_ERROR("read_mapping_page failed: %d\n", ret); | 1910 | DRM_ERROR("read_mapping_page failed: %d\n", ret); |
1443 | i915_gem_object_free_page_list(obj); | 1911 | i915_gem_object_put_pages(obj); |
1444 | return ret; | 1912 | return ret; |
1445 | } | 1913 | } |
1446 | obj_priv->page_list[i] = page; | 1914 | obj_priv->pages[i] = page; |
1447 | } | 1915 | } |
1448 | return 0; | 1916 | return 0; |
1449 | } | 1917 | } |
@@ -1766,7 +2234,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) | |||
1766 | DRM_INFO("Binding object of size %d at 0x%08x\n", | 2234 | DRM_INFO("Binding object of size %d at 0x%08x\n", |
1767 | obj->size, obj_priv->gtt_offset); | 2235 | obj->size, obj_priv->gtt_offset); |
1768 | #endif | 2236 | #endif |
1769 | ret = i915_gem_object_get_page_list(obj); | 2237 | ret = i915_gem_object_get_pages(obj); |
1770 | if (ret) { | 2238 | if (ret) { |
1771 | drm_mm_put_block(obj_priv->gtt_space); | 2239 | drm_mm_put_block(obj_priv->gtt_space); |
1772 | obj_priv->gtt_space = NULL; | 2240 | obj_priv->gtt_space = NULL; |
@@ -1778,12 +2246,12 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) | |||
1778 | * into the GTT. | 2246 | * into the GTT. |
1779 | */ | 2247 | */ |
1780 | obj_priv->agp_mem = drm_agp_bind_pages(dev, | 2248 | obj_priv->agp_mem = drm_agp_bind_pages(dev, |
1781 | obj_priv->page_list, | 2249 | obj_priv->pages, |
1782 | page_count, | 2250 | page_count, |
1783 | obj_priv->gtt_offset, | 2251 | obj_priv->gtt_offset, |
1784 | obj_priv->agp_type); | 2252 | obj_priv->agp_type); |
1785 | if (obj_priv->agp_mem == NULL) { | 2253 | if (obj_priv->agp_mem == NULL) { |
1786 | i915_gem_object_free_page_list(obj); | 2254 | i915_gem_object_put_pages(obj); |
1787 | drm_mm_put_block(obj_priv->gtt_space); | 2255 | drm_mm_put_block(obj_priv->gtt_space); |
1788 | obj_priv->gtt_space = NULL; | 2256 | obj_priv->gtt_space = NULL; |
1789 | return -ENOMEM; | 2257 | return -ENOMEM; |
@@ -1810,10 +2278,10 @@ i915_gem_clflush_object(struct drm_gem_object *obj) | |||
1810 | * to GPU, and we can ignore the cache flush because it'll happen | 2278 | * to GPU, and we can ignore the cache flush because it'll happen |
1811 | * again at bind time. | 2279 | * again at bind time. |
1812 | */ | 2280 | */ |
1813 | if (obj_priv->page_list == NULL) | 2281 | if (obj_priv->pages == NULL) |
1814 | return; | 2282 | return; |
1815 | 2283 | ||
1816 | drm_clflush_pages(obj_priv->page_list, obj->size / PAGE_SIZE); | 2284 | drm_clflush_pages(obj_priv->pages, obj->size / PAGE_SIZE); |
1817 | } | 2285 | } |
1818 | 2286 | ||
1819 | /** Flushes any GPU write domain for the object if it's dirty. */ | 2287 | /** Flushes any GPU write domain for the object if it's dirty. */ |
@@ -1913,7 +2381,6 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) | |||
1913 | static int | 2381 | static int |
1914 | i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) | 2382 | i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) |
1915 | { | 2383 | { |
1916 | struct drm_device *dev = obj->dev; | ||
1917 | int ret; | 2384 | int ret; |
1918 | 2385 | ||
1919 | i915_gem_object_flush_gpu_write_domain(obj); | 2386 | i915_gem_object_flush_gpu_write_domain(obj); |
@@ -1932,7 +2399,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) | |||
1932 | /* Flush the CPU cache if it's still invalid. */ | 2399 | /* Flush the CPU cache if it's still invalid. */ |
1933 | if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) { | 2400 | if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) { |
1934 | i915_gem_clflush_object(obj); | 2401 | i915_gem_clflush_object(obj); |
1935 | drm_agp_chipset_flush(dev); | ||
1936 | 2402 | ||
1937 | obj->read_domains |= I915_GEM_DOMAIN_CPU; | 2403 | obj->read_domains |= I915_GEM_DOMAIN_CPU; |
1938 | } | 2404 | } |
@@ -2144,7 +2610,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) | |||
2144 | static void | 2610 | static void |
2145 | i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) | 2611 | i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) |
2146 | { | 2612 | { |
2147 | struct drm_device *dev = obj->dev; | ||
2148 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2613 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
2149 | 2614 | ||
2150 | if (!obj_priv->page_cpu_valid) | 2615 | if (!obj_priv->page_cpu_valid) |
@@ -2158,9 +2623,8 @@ i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) | |||
2158 | for (i = 0; i <= (obj->size - 1) / PAGE_SIZE; i++) { | 2623 | for (i = 0; i <= (obj->size - 1) / PAGE_SIZE; i++) { |
2159 | if (obj_priv->page_cpu_valid[i]) | 2624 | if (obj_priv->page_cpu_valid[i]) |
2160 | continue; | 2625 | continue; |
2161 | drm_clflush_pages(obj_priv->page_list + i, 1); | 2626 | drm_clflush_pages(obj_priv->pages + i, 1); |
2162 | } | 2627 | } |
2163 | drm_agp_chipset_flush(dev); | ||
2164 | } | 2628 | } |
2165 | 2629 | ||
2166 | /* Free the page_cpu_valid mappings which are now stale, whether | 2630 | /* Free the page_cpu_valid mappings which are now stale, whether |
@@ -2224,7 +2688,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, | |||
2224 | if (obj_priv->page_cpu_valid[i]) | 2688 | if (obj_priv->page_cpu_valid[i]) |
2225 | continue; | 2689 | continue; |
2226 | 2690 | ||
2227 | drm_clflush_pages(obj_priv->page_list + i, 1); | 2691 | drm_clflush_pages(obj_priv->pages + i, 1); |
2228 | 2692 | ||
2229 | obj_priv->page_cpu_valid[i] = 1; | 2693 | obj_priv->page_cpu_valid[i] = 1; |
2230 | } | 2694 | } |
@@ -2245,12 +2709,11 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, | |||
2245 | static int | 2709 | static int |
2246 | i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | 2710 | i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, |
2247 | struct drm_file *file_priv, | 2711 | struct drm_file *file_priv, |
2248 | struct drm_i915_gem_exec_object *entry) | 2712 | struct drm_i915_gem_exec_object *entry, |
2713 | struct drm_i915_gem_relocation_entry *relocs) | ||
2249 | { | 2714 | { |
2250 | struct drm_device *dev = obj->dev; | 2715 | struct drm_device *dev = obj->dev; |
2251 | drm_i915_private_t *dev_priv = dev->dev_private; | 2716 | drm_i915_private_t *dev_priv = dev->dev_private; |
2252 | struct drm_i915_gem_relocation_entry reloc; | ||
2253 | struct drm_i915_gem_relocation_entry __user *relocs; | ||
2254 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2717 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
2255 | int i, ret; | 2718 | int i, ret; |
2256 | void __iomem *reloc_page; | 2719 | void __iomem *reloc_page; |
@@ -2262,25 +2725,18 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
2262 | 2725 | ||
2263 | entry->offset = obj_priv->gtt_offset; | 2726 | entry->offset = obj_priv->gtt_offset; |
2264 | 2727 | ||
2265 | relocs = (struct drm_i915_gem_relocation_entry __user *) | ||
2266 | (uintptr_t) entry->relocs_ptr; | ||
2267 | /* Apply the relocations, using the GTT aperture to avoid cache | 2728 | /* Apply the relocations, using the GTT aperture to avoid cache |
2268 | * flushing requirements. | 2729 | * flushing requirements. |
2269 | */ | 2730 | */ |
2270 | for (i = 0; i < entry->relocation_count; i++) { | 2731 | for (i = 0; i < entry->relocation_count; i++) { |
2732 | struct drm_i915_gem_relocation_entry *reloc= &relocs[i]; | ||
2271 | struct drm_gem_object *target_obj; | 2733 | struct drm_gem_object *target_obj; |
2272 | struct drm_i915_gem_object *target_obj_priv; | 2734 | struct drm_i915_gem_object *target_obj_priv; |
2273 | uint32_t reloc_val, reloc_offset; | 2735 | uint32_t reloc_val, reloc_offset; |
2274 | uint32_t __iomem *reloc_entry; | 2736 | uint32_t __iomem *reloc_entry; |
2275 | 2737 | ||
2276 | ret = copy_from_user(&reloc, relocs + i, sizeof(reloc)); | ||
2277 | if (ret != 0) { | ||
2278 | i915_gem_object_unpin(obj); | ||
2279 | return ret; | ||
2280 | } | ||
2281 | |||
2282 | target_obj = drm_gem_object_lookup(obj->dev, file_priv, | 2738 | target_obj = drm_gem_object_lookup(obj->dev, file_priv, |
2283 | reloc.target_handle); | 2739 | reloc->target_handle); |
2284 | if (target_obj == NULL) { | 2740 | if (target_obj == NULL) { |
2285 | i915_gem_object_unpin(obj); | 2741 | i915_gem_object_unpin(obj); |
2286 | return -EBADF; | 2742 | return -EBADF; |
@@ -2292,53 +2748,53 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
2292 | */ | 2748 | */ |
2293 | if (target_obj_priv->gtt_space == NULL) { | 2749 | if (target_obj_priv->gtt_space == NULL) { |
2294 | DRM_ERROR("No GTT space found for object %d\n", | 2750 | DRM_ERROR("No GTT space found for object %d\n", |
2295 | reloc.target_handle); | 2751 | reloc->target_handle); |
2296 | drm_gem_object_unreference(target_obj); | 2752 | drm_gem_object_unreference(target_obj); |
2297 | i915_gem_object_unpin(obj); | 2753 | i915_gem_object_unpin(obj); |
2298 | return -EINVAL; | 2754 | return -EINVAL; |
2299 | } | 2755 | } |
2300 | 2756 | ||
2301 | if (reloc.offset > obj->size - 4) { | 2757 | if (reloc->offset > obj->size - 4) { |
2302 | DRM_ERROR("Relocation beyond object bounds: " | 2758 | DRM_ERROR("Relocation beyond object bounds: " |
2303 | "obj %p target %d offset %d size %d.\n", | 2759 | "obj %p target %d offset %d size %d.\n", |
2304 | obj, reloc.target_handle, | 2760 | obj, reloc->target_handle, |
2305 | (int) reloc.offset, (int) obj->size); | 2761 | (int) reloc->offset, (int) obj->size); |
2306 | drm_gem_object_unreference(target_obj); | 2762 | drm_gem_object_unreference(target_obj); |
2307 | i915_gem_object_unpin(obj); | 2763 | i915_gem_object_unpin(obj); |
2308 | return -EINVAL; | 2764 | return -EINVAL; |
2309 | } | 2765 | } |
2310 | if (reloc.offset & 3) { | 2766 | if (reloc->offset & 3) { |
2311 | DRM_ERROR("Relocation not 4-byte aligned: " | 2767 | DRM_ERROR("Relocation not 4-byte aligned: " |
2312 | "obj %p target %d offset %d.\n", | 2768 | "obj %p target %d offset %d.\n", |
2313 | obj, reloc.target_handle, | 2769 | obj, reloc->target_handle, |
2314 | (int) reloc.offset); | 2770 | (int) reloc->offset); |
2315 | drm_gem_object_unreference(target_obj); | 2771 | drm_gem_object_unreference(target_obj); |
2316 | i915_gem_object_unpin(obj); | 2772 | i915_gem_object_unpin(obj); |
2317 | return -EINVAL; | 2773 | return -EINVAL; |
2318 | } | 2774 | } |
2319 | 2775 | ||
2320 | if (reloc.write_domain & I915_GEM_DOMAIN_CPU || | 2776 | if (reloc->write_domain & I915_GEM_DOMAIN_CPU || |
2321 | reloc.read_domains & I915_GEM_DOMAIN_CPU) { | 2777 | reloc->read_domains & I915_GEM_DOMAIN_CPU) { |
2322 | DRM_ERROR("reloc with read/write CPU domains: " | 2778 | DRM_ERROR("reloc with read/write CPU domains: " |
2323 | "obj %p target %d offset %d " | 2779 | "obj %p target %d offset %d " |
2324 | "read %08x write %08x", | 2780 | "read %08x write %08x", |
2325 | obj, reloc.target_handle, | 2781 | obj, reloc->target_handle, |
2326 | (int) reloc.offset, | 2782 | (int) reloc->offset, |
2327 | reloc.read_domains, | 2783 | reloc->read_domains, |
2328 | reloc.write_domain); | 2784 | reloc->write_domain); |
2329 | drm_gem_object_unreference(target_obj); | 2785 | drm_gem_object_unreference(target_obj); |
2330 | i915_gem_object_unpin(obj); | 2786 | i915_gem_object_unpin(obj); |
2331 | return -EINVAL; | 2787 | return -EINVAL; |
2332 | } | 2788 | } |
2333 | 2789 | ||
2334 | if (reloc.write_domain && target_obj->pending_write_domain && | 2790 | if (reloc->write_domain && target_obj->pending_write_domain && |
2335 | reloc.write_domain != target_obj->pending_write_domain) { | 2791 | reloc->write_domain != target_obj->pending_write_domain) { |
2336 | DRM_ERROR("Write domain conflict: " | 2792 | DRM_ERROR("Write domain conflict: " |
2337 | "obj %p target %d offset %d " | 2793 | "obj %p target %d offset %d " |
2338 | "new %08x old %08x\n", | 2794 | "new %08x old %08x\n", |
2339 | obj, reloc.target_handle, | 2795 | obj, reloc->target_handle, |
2340 | (int) reloc.offset, | 2796 | (int) reloc->offset, |
2341 | reloc.write_domain, | 2797 | reloc->write_domain, |
2342 | target_obj->pending_write_domain); | 2798 | target_obj->pending_write_domain); |
2343 | drm_gem_object_unreference(target_obj); | 2799 | drm_gem_object_unreference(target_obj); |
2344 | i915_gem_object_unpin(obj); | 2800 | i915_gem_object_unpin(obj); |
@@ -2351,22 +2807,22 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
2351 | "presumed %08x delta %08x\n", | 2807 | "presumed %08x delta %08x\n", |
2352 | __func__, | 2808 | __func__, |
2353 | obj, | 2809 | obj, |
2354 | (int) reloc.offset, | 2810 | (int) reloc->offset, |
2355 | (int) reloc.target_handle, | 2811 | (int) reloc->target_handle, |
2356 | (int) reloc.read_domains, | 2812 | (int) reloc->read_domains, |
2357 | (int) reloc.write_domain, | 2813 | (int) reloc->write_domain, |
2358 | (int) target_obj_priv->gtt_offset, | 2814 | (int) target_obj_priv->gtt_offset, |
2359 | (int) reloc.presumed_offset, | 2815 | (int) reloc->presumed_offset, |
2360 | reloc.delta); | 2816 | reloc->delta); |
2361 | #endif | 2817 | #endif |
2362 | 2818 | ||
2363 | target_obj->pending_read_domains |= reloc.read_domains; | 2819 | target_obj->pending_read_domains |= reloc->read_domains; |
2364 | target_obj->pending_write_domain |= reloc.write_domain; | 2820 | target_obj->pending_write_domain |= reloc->write_domain; |
2365 | 2821 | ||
2366 | /* If the relocation already has the right value in it, no | 2822 | /* If the relocation already has the right value in it, no |
2367 | * more work needs to be done. | 2823 | * more work needs to be done. |
2368 | */ | 2824 | */ |
2369 | if (target_obj_priv->gtt_offset == reloc.presumed_offset) { | 2825 | if (target_obj_priv->gtt_offset == reloc->presumed_offset) { |
2370 | drm_gem_object_unreference(target_obj); | 2826 | drm_gem_object_unreference(target_obj); |
2371 | continue; | 2827 | continue; |
2372 | } | 2828 | } |
@@ -2381,32 +2837,26 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
2381 | /* Map the page containing the relocation we're going to | 2837 | /* Map the page containing the relocation we're going to |
2382 | * perform. | 2838 | * perform. |
2383 | */ | 2839 | */ |
2384 | reloc_offset = obj_priv->gtt_offset + reloc.offset; | 2840 | reloc_offset = obj_priv->gtt_offset + reloc->offset; |
2385 | reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, | 2841 | reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, |
2386 | (reloc_offset & | 2842 | (reloc_offset & |
2387 | ~(PAGE_SIZE - 1))); | 2843 | ~(PAGE_SIZE - 1))); |
2388 | reloc_entry = (uint32_t __iomem *)(reloc_page + | 2844 | reloc_entry = (uint32_t __iomem *)(reloc_page + |
2389 | (reloc_offset & (PAGE_SIZE - 1))); | 2845 | (reloc_offset & (PAGE_SIZE - 1))); |
2390 | reloc_val = target_obj_priv->gtt_offset + reloc.delta; | 2846 | reloc_val = target_obj_priv->gtt_offset + reloc->delta; |
2391 | 2847 | ||
2392 | #if WATCH_BUF | 2848 | #if WATCH_BUF |
2393 | DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n", | 2849 | DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n", |
2394 | obj, (unsigned int) reloc.offset, | 2850 | obj, (unsigned int) reloc->offset, |
2395 | readl(reloc_entry), reloc_val); | 2851 | readl(reloc_entry), reloc_val); |
2396 | #endif | 2852 | #endif |
2397 | writel(reloc_val, reloc_entry); | 2853 | writel(reloc_val, reloc_entry); |
2398 | io_mapping_unmap_atomic(reloc_page); | 2854 | io_mapping_unmap_atomic(reloc_page); |
2399 | 2855 | ||
2400 | /* Write the updated presumed offset for this entry back out | 2856 | /* The updated presumed offset for this entry will be |
2401 | * to the user. | 2857 | * copied back out to the user. |
2402 | */ | 2858 | */ |
2403 | reloc.presumed_offset = target_obj_priv->gtt_offset; | 2859 | reloc->presumed_offset = target_obj_priv->gtt_offset; |
2404 | ret = copy_to_user(relocs + i, &reloc, sizeof(reloc)); | ||
2405 | if (ret != 0) { | ||
2406 | drm_gem_object_unreference(target_obj); | ||
2407 | i915_gem_object_unpin(obj); | ||
2408 | return ret; | ||
2409 | } | ||
2410 | 2860 | ||
2411 | drm_gem_object_unreference(target_obj); | 2861 | drm_gem_object_unreference(target_obj); |
2412 | } | 2862 | } |
@@ -2423,11 +2873,10 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
2423 | static int | 2873 | static int |
2424 | i915_dispatch_gem_execbuffer(struct drm_device *dev, | 2874 | i915_dispatch_gem_execbuffer(struct drm_device *dev, |
2425 | struct drm_i915_gem_execbuffer *exec, | 2875 | struct drm_i915_gem_execbuffer *exec, |
2876 | struct drm_clip_rect *cliprects, | ||
2426 | uint64_t exec_offset) | 2877 | uint64_t exec_offset) |
2427 | { | 2878 | { |
2428 | drm_i915_private_t *dev_priv = dev->dev_private; | 2879 | drm_i915_private_t *dev_priv = dev->dev_private; |
2429 | struct drm_clip_rect __user *boxes = (struct drm_clip_rect __user *) | ||
2430 | (uintptr_t) exec->cliprects_ptr; | ||
2431 | int nbox = exec->num_cliprects; | 2880 | int nbox = exec->num_cliprects; |
2432 | int i = 0, count; | 2881 | int i = 0, count; |
2433 | uint32_t exec_start, exec_len; | 2882 | uint32_t exec_start, exec_len; |
@@ -2448,7 +2897,7 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, | |||
2448 | 2897 | ||
2449 | for (i = 0; i < count; i++) { | 2898 | for (i = 0; i < count; i++) { |
2450 | if (i < nbox) { | 2899 | if (i < nbox) { |
2451 | int ret = i915_emit_box(dev, boxes, i, | 2900 | int ret = i915_emit_box(dev, cliprects, i, |
2452 | exec->DR1, exec->DR4); | 2901 | exec->DR1, exec->DR4); |
2453 | if (ret) | 2902 | if (ret) |
2454 | return ret; | 2903 | return ret; |
@@ -2504,6 +2953,75 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) | |||
2504 | return ret; | 2953 | return ret; |
2505 | } | 2954 | } |
2506 | 2955 | ||
2956 | static int | ||
2957 | i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, | ||
2958 | uint32_t buffer_count, | ||
2959 | struct drm_i915_gem_relocation_entry **relocs) | ||
2960 | { | ||
2961 | uint32_t reloc_count = 0, reloc_index = 0, i; | ||
2962 | int ret; | ||
2963 | |||
2964 | *relocs = NULL; | ||
2965 | for (i = 0; i < buffer_count; i++) { | ||
2966 | if (reloc_count + exec_list[i].relocation_count < reloc_count) | ||
2967 | return -EINVAL; | ||
2968 | reloc_count += exec_list[i].relocation_count; | ||
2969 | } | ||
2970 | |||
2971 | *relocs = drm_calloc(reloc_count, sizeof(**relocs), DRM_MEM_DRIVER); | ||
2972 | if (*relocs == NULL) | ||
2973 | return -ENOMEM; | ||
2974 | |||
2975 | for (i = 0; i < buffer_count; i++) { | ||
2976 | struct drm_i915_gem_relocation_entry __user *user_relocs; | ||
2977 | |||
2978 | user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; | ||
2979 | |||
2980 | ret = copy_from_user(&(*relocs)[reloc_index], | ||
2981 | user_relocs, | ||
2982 | exec_list[i].relocation_count * | ||
2983 | sizeof(**relocs)); | ||
2984 | if (ret != 0) { | ||
2985 | drm_free(*relocs, reloc_count * sizeof(**relocs), | ||
2986 | DRM_MEM_DRIVER); | ||
2987 | *relocs = NULL; | ||
2988 | return ret; | ||
2989 | } | ||
2990 | |||
2991 | reloc_index += exec_list[i].relocation_count; | ||
2992 | } | ||
2993 | |||
2994 | return ret; | ||
2995 | } | ||
2996 | |||
2997 | static int | ||
2998 | i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object *exec_list, | ||
2999 | uint32_t buffer_count, | ||
3000 | struct drm_i915_gem_relocation_entry *relocs) | ||
3001 | { | ||
3002 | uint32_t reloc_count = 0, i; | ||
3003 | int ret; | ||
3004 | |||
3005 | for (i = 0; i < buffer_count; i++) { | ||
3006 | struct drm_i915_gem_relocation_entry __user *user_relocs; | ||
3007 | |||
3008 | user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; | ||
3009 | |||
3010 | if (ret == 0) { | ||
3011 | ret = copy_to_user(user_relocs, | ||
3012 | &relocs[reloc_count], | ||
3013 | exec_list[i].relocation_count * | ||
3014 | sizeof(*relocs)); | ||
3015 | } | ||
3016 | |||
3017 | reloc_count += exec_list[i].relocation_count; | ||
3018 | } | ||
3019 | |||
3020 | drm_free(relocs, reloc_count * sizeof(*relocs), DRM_MEM_DRIVER); | ||
3021 | |||
3022 | return ret; | ||
3023 | } | ||
3024 | |||
2507 | int | 3025 | int |
2508 | i915_gem_execbuffer(struct drm_device *dev, void *data, | 3026 | i915_gem_execbuffer(struct drm_device *dev, void *data, |
2509 | struct drm_file *file_priv) | 3027 | struct drm_file *file_priv) |
@@ -2515,9 +3033,11 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
2515 | struct drm_gem_object **object_list = NULL; | 3033 | struct drm_gem_object **object_list = NULL; |
2516 | struct drm_gem_object *batch_obj; | 3034 | struct drm_gem_object *batch_obj; |
2517 | struct drm_i915_gem_object *obj_priv; | 3035 | struct drm_i915_gem_object *obj_priv; |
2518 | int ret, i, pinned = 0; | 3036 | struct drm_clip_rect *cliprects = NULL; |
3037 | struct drm_i915_gem_relocation_entry *relocs; | ||
3038 | int ret, ret2, i, pinned = 0; | ||
2519 | uint64_t exec_offset; | 3039 | uint64_t exec_offset; |
2520 | uint32_t seqno, flush_domains; | 3040 | uint32_t seqno, flush_domains, reloc_index; |
2521 | int pin_tries; | 3041 | int pin_tries; |
2522 | 3042 | ||
2523 | #if WATCH_EXEC | 3043 | #if WATCH_EXEC |
@@ -2551,6 +3071,28 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
2551 | goto pre_mutex_err; | 3071 | goto pre_mutex_err; |
2552 | } | 3072 | } |
2553 | 3073 | ||
3074 | if (args->num_cliprects != 0) { | ||
3075 | cliprects = drm_calloc(args->num_cliprects, sizeof(*cliprects), | ||
3076 | DRM_MEM_DRIVER); | ||
3077 | if (cliprects == NULL) | ||
3078 | goto pre_mutex_err; | ||
3079 | |||
3080 | ret = copy_from_user(cliprects, | ||
3081 | (struct drm_clip_rect __user *) | ||
3082 | (uintptr_t) args->cliprects_ptr, | ||
3083 | sizeof(*cliprects) * args->num_cliprects); | ||
3084 | if (ret != 0) { | ||
3085 | DRM_ERROR("copy %d cliprects failed: %d\n", | ||
3086 | args->num_cliprects, ret); | ||
3087 | goto pre_mutex_err; | ||
3088 | } | ||
3089 | } | ||
3090 | |||
3091 | ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count, | ||
3092 | &relocs); | ||
3093 | if (ret != 0) | ||
3094 | goto pre_mutex_err; | ||
3095 | |||
2554 | mutex_lock(&dev->struct_mutex); | 3096 | mutex_lock(&dev->struct_mutex); |
2555 | 3097 | ||
2556 | i915_verify_inactive(dev, __FILE__, __LINE__); | 3098 | i915_verify_inactive(dev, __FILE__, __LINE__); |
@@ -2593,15 +3135,19 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
2593 | /* Pin and relocate */ | 3135 | /* Pin and relocate */ |
2594 | for (pin_tries = 0; ; pin_tries++) { | 3136 | for (pin_tries = 0; ; pin_tries++) { |
2595 | ret = 0; | 3137 | ret = 0; |
3138 | reloc_index = 0; | ||
3139 | |||
2596 | for (i = 0; i < args->buffer_count; i++) { | 3140 | for (i = 0; i < args->buffer_count; i++) { |
2597 | object_list[i]->pending_read_domains = 0; | 3141 | object_list[i]->pending_read_domains = 0; |
2598 | object_list[i]->pending_write_domain = 0; | 3142 | object_list[i]->pending_write_domain = 0; |
2599 | ret = i915_gem_object_pin_and_relocate(object_list[i], | 3143 | ret = i915_gem_object_pin_and_relocate(object_list[i], |
2600 | file_priv, | 3144 | file_priv, |
2601 | &exec_list[i]); | 3145 | &exec_list[i], |
3146 | &relocs[reloc_index]); | ||
2602 | if (ret) | 3147 | if (ret) |
2603 | break; | 3148 | break; |
2604 | pinned = i + 1; | 3149 | pinned = i + 1; |
3150 | reloc_index += exec_list[i].relocation_count; | ||
2605 | } | 3151 | } |
2606 | /* success */ | 3152 | /* success */ |
2607 | if (ret == 0) | 3153 | if (ret == 0) |
@@ -2687,7 +3233,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
2687 | #endif | 3233 | #endif |
2688 | 3234 | ||
2689 | /* Exec the batchbuffer */ | 3235 | /* Exec the batchbuffer */ |
2690 | ret = i915_dispatch_gem_execbuffer(dev, args, exec_offset); | 3236 | ret = i915_dispatch_gem_execbuffer(dev, args, cliprects, exec_offset); |
2691 | if (ret) { | 3237 | if (ret) { |
2692 | DRM_ERROR("dispatch failed %d\n", ret); | 3238 | DRM_ERROR("dispatch failed %d\n", ret); |
2693 | goto err; | 3239 | goto err; |
@@ -2751,11 +3297,27 @@ err: | |||
2751 | args->buffer_count, ret); | 3297 | args->buffer_count, ret); |
2752 | } | 3298 | } |
2753 | 3299 | ||
3300 | /* Copy the updated relocations out regardless of current error | ||
3301 | * state. Failure to update the relocs would mean that the next | ||
3302 | * time userland calls execbuf, it would do so with presumed offset | ||
3303 | * state that didn't match the actual object state. | ||
3304 | */ | ||
3305 | ret2 = i915_gem_put_relocs_to_user(exec_list, args->buffer_count, | ||
3306 | relocs); | ||
3307 | if (ret2 != 0) { | ||
3308 | DRM_ERROR("Failed to copy relocations back out: %d\n", ret2); | ||
3309 | |||
3310 | if (ret == 0) | ||
3311 | ret = ret2; | ||
3312 | } | ||
3313 | |||
2754 | pre_mutex_err: | 3314 | pre_mutex_err: |
2755 | drm_free(object_list, sizeof(*object_list) * args->buffer_count, | 3315 | drm_free(object_list, sizeof(*object_list) * args->buffer_count, |
2756 | DRM_MEM_DRIVER); | 3316 | DRM_MEM_DRIVER); |
2757 | drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, | 3317 | drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, |
2758 | DRM_MEM_DRIVER); | 3318 | DRM_MEM_DRIVER); |
3319 | drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, | ||
3320 | DRM_MEM_DRIVER); | ||
2759 | 3321 | ||
2760 | return ret; | 3322 | return ret; |
2761 | } | 3323 | } |
@@ -3192,7 +3754,7 @@ i915_gem_init_hws(struct drm_device *dev) | |||
3192 | 3754 | ||
3193 | dev_priv->status_gfx_addr = obj_priv->gtt_offset; | 3755 | dev_priv->status_gfx_addr = obj_priv->gtt_offset; |
3194 | 3756 | ||
3195 | dev_priv->hw_status_page = kmap(obj_priv->page_list[0]); | 3757 | dev_priv->hw_status_page = kmap(obj_priv->pages[0]); |
3196 | if (dev_priv->hw_status_page == NULL) { | 3758 | if (dev_priv->hw_status_page == NULL) { |
3197 | DRM_ERROR("Failed to map status page.\n"); | 3759 | DRM_ERROR("Failed to map status page.\n"); |
3198 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); | 3760 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); |
@@ -3222,7 +3784,7 @@ i915_gem_cleanup_hws(struct drm_device *dev) | |||
3222 | obj = dev_priv->hws_obj; | 3784 | obj = dev_priv->hws_obj; |
3223 | obj_priv = obj->driver_private; | 3785 | obj_priv = obj->driver_private; |
3224 | 3786 | ||
3225 | kunmap(obj_priv->page_list[0]); | 3787 | kunmap(obj_priv->pages[0]); |
3226 | i915_gem_object_unpin(obj); | 3788 | i915_gem_object_unpin(obj); |
3227 | drm_gem_object_unreference(obj); | 3789 | drm_gem_object_unreference(obj); |
3228 | dev_priv->hws_obj = NULL; | 3790 | dev_priv->hws_obj = NULL; |
@@ -3525,20 +4087,20 @@ void i915_gem_detach_phys_object(struct drm_device *dev, | |||
3525 | if (!obj_priv->phys_obj) | 4087 | if (!obj_priv->phys_obj) |
3526 | return; | 4088 | return; |
3527 | 4089 | ||
3528 | ret = i915_gem_object_get_page_list(obj); | 4090 | ret = i915_gem_object_get_pages(obj); |
3529 | if (ret) | 4091 | if (ret) |
3530 | goto out; | 4092 | goto out; |
3531 | 4093 | ||
3532 | page_count = obj->size / PAGE_SIZE; | 4094 | page_count = obj->size / PAGE_SIZE; |
3533 | 4095 | ||
3534 | for (i = 0; i < page_count; i++) { | 4096 | for (i = 0; i < page_count; i++) { |
3535 | char *dst = kmap_atomic(obj_priv->page_list[i], KM_USER0); | 4097 | char *dst = kmap_atomic(obj_priv->pages[i], KM_USER0); |
3536 | char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); | 4098 | char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); |
3537 | 4099 | ||
3538 | memcpy(dst, src, PAGE_SIZE); | 4100 | memcpy(dst, src, PAGE_SIZE); |
3539 | kunmap_atomic(dst, KM_USER0); | 4101 | kunmap_atomic(dst, KM_USER0); |
3540 | } | 4102 | } |
3541 | drm_clflush_pages(obj_priv->page_list, page_count); | 4103 | drm_clflush_pages(obj_priv->pages, page_count); |
3542 | drm_agp_chipset_flush(dev); | 4104 | drm_agp_chipset_flush(dev); |
3543 | out: | 4105 | out: |
3544 | obj_priv->phys_obj->cur_obj = NULL; | 4106 | obj_priv->phys_obj->cur_obj = NULL; |
@@ -3581,7 +4143,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, | |||
3581 | obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1]; | 4143 | obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1]; |
3582 | obj_priv->phys_obj->cur_obj = obj; | 4144 | obj_priv->phys_obj->cur_obj = obj; |
3583 | 4145 | ||
3584 | ret = i915_gem_object_get_page_list(obj); | 4146 | ret = i915_gem_object_get_pages(obj); |
3585 | if (ret) { | 4147 | if (ret) { |
3586 | DRM_ERROR("failed to get page list\n"); | 4148 | DRM_ERROR("failed to get page list\n"); |
3587 | goto out; | 4149 | goto out; |
@@ -3590,7 +4152,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, | |||
3590 | page_count = obj->size / PAGE_SIZE; | 4152 | page_count = obj->size / PAGE_SIZE; |
3591 | 4153 | ||
3592 | for (i = 0; i < page_count; i++) { | 4154 | for (i = 0; i < page_count; i++) { |
3593 | char *src = kmap_atomic(obj_priv->page_list[i], KM_USER0); | 4155 | char *src = kmap_atomic(obj_priv->pages[i], KM_USER0); |
3594 | char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); | 4156 | char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); |
3595 | 4157 | ||
3596 | memcpy(dst, src, PAGE_SIZE); | 4158 | memcpy(dst, src, PAGE_SIZE); |