aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-11-03 13:15:40 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-11-03 13:15:40 -0500
commitda4a22cba7cb2d922691214aed6b1977f04efaff (patch)
tree89d3f02b13cd1eb280a33240878880f91066bac2 /drivers/gpu/drm/i915
parent20ebc0073b0fb63ce4a27ca761418ecfdecaadb7 (diff)
parente5beae16901795223d677f15aa2fe192976278ee (diff)
Merge branch 'io-mappings-for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'io-mappings-for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: io mapping: clean up #ifdefs io mapping: improve documentation i915: use io-mapping interfaces instead of a variety of mapping kludges resources: add io-mapping functions to dynamically map large device apertures x86: add iomap_atomic*()/iounmap_atomic() on 32-bit using fixmaps
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h3
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c174
2 files changed, 83 insertions, 94 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index cc8a9f3f7a60..572dcd0e3e0d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -31,6 +31,7 @@
31#define _I915_DRV_H_ 31#define _I915_DRV_H_
32 32
33#include "i915_reg.h" 33#include "i915_reg.h"
34#include <linux/io-mapping.h>
34 35
35/* General customization: 36/* General customization:
36 */ 37 */
@@ -246,6 +247,8 @@ typedef struct drm_i915_private {
246 struct { 247 struct {
247 struct drm_mm gtt_space; 248 struct drm_mm gtt_space;
248 249
250 struct io_mapping *gtt_mapping;
251
249 /** 252 /**
250 * List of objects currently involved in rendering from the 253 * List of objects currently involved in rendering from the
251 * ringbuffer. 254 * ringbuffer.
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index c1733ac4a7f5..b0ec73fa6a93 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -193,35 +193,50 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
193 return 0; 193 return 0;
194} 194}
195 195
196/* 196/* This is the fast write path which cannot handle
197 * Try to write quickly with an atomic kmap. Return true on success. 197 * page faults in the source data
198 *
199 * If this fails (which includes a partial write), we'll redo the whole
200 * thing with the slow version.
201 *
202 * This is a workaround for the low performance of iounmap (approximate
203 * 10% cpu cost on normal 3D workloads). kmap_atomic on HIGHMEM kernels
204 * happens to let us map card memory without taking IPIs. When the vmap
205 * rework lands we should be able to dump this hack.
206 */ 198 */
207static inline int fast_user_write(unsigned long pfn, char __user *user_data, 199
208 int l, int o) 200static inline int
201fast_user_write(struct io_mapping *mapping,
202 loff_t page_base, int page_offset,
203 char __user *user_data,
204 int length)
209{ 205{
210#ifdef CONFIG_HIGHMEM
211 unsigned long unwritten;
212 char *vaddr_atomic; 206 char *vaddr_atomic;
207 unsigned long unwritten;
213 208
214 vaddr_atomic = kmap_atomic_pfn(pfn, KM_USER0); 209 vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base);
215#if WATCH_PWRITE 210 unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
216 DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n", 211 user_data, length);
217 i, o, l, pfn, vaddr_atomic); 212 io_mapping_unmap_atomic(vaddr_atomic);
218#endif 213 if (unwritten)
219 unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + o, user_data, l); 214 return -EFAULT;
220 kunmap_atomic(vaddr_atomic, KM_USER0); 215 return 0;
221 return !unwritten; 216}
222#else 217
218/* Here's the write path which can sleep for
219 * page faults
220 */
221
222static inline int
223slow_user_write(struct io_mapping *mapping,
224 loff_t page_base, int page_offset,
225 char __user *user_data,
226 int length)
227{
228 char __iomem *vaddr;
229 unsigned long unwritten;
230
231 vaddr = io_mapping_map_wc(mapping, page_base);
232 if (vaddr == NULL)
233 return -EFAULT;
234 unwritten = __copy_from_user(vaddr + page_offset,
235 user_data, length);
236 io_mapping_unmap(vaddr);
237 if (unwritten)
238 return -EFAULT;
223 return 0; 239 return 0;
224#endif
225} 240}
226 241
227static int 242static int
@@ -230,10 +245,12 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
230 struct drm_file *file_priv) 245 struct drm_file *file_priv)
231{ 246{
232 struct drm_i915_gem_object *obj_priv = obj->driver_private; 247 struct drm_i915_gem_object *obj_priv = obj->driver_private;
248 drm_i915_private_t *dev_priv = dev->dev_private;
233 ssize_t remain; 249 ssize_t remain;
234 loff_t offset; 250 loff_t offset, page_base;
235 char __user *user_data; 251 char __user *user_data;
236 int ret = 0; 252 int page_offset, page_length;
253 int ret;
237 254
238 user_data = (char __user *) (uintptr_t) args->data_ptr; 255 user_data = (char __user *) (uintptr_t) args->data_ptr;
239 remain = args->size; 256 remain = args->size;
@@ -257,57 +274,37 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
257 obj_priv->dirty = 1; 274 obj_priv->dirty = 1;
258 275
259 while (remain > 0) { 276 while (remain > 0) {
260 unsigned long pfn;
261 int i, o, l;
262
263 /* Operation in this page 277 /* Operation in this page
264 * 278 *
265 * i = page number 279 * page_base = page offset within aperture
266 * o = offset within page 280 * page_offset = offset within page
267 * l = bytes to copy 281 * page_length = bytes to copy for this page
268 */ 282 */
269 i = offset >> PAGE_SHIFT; 283 page_base = (offset & ~(PAGE_SIZE-1));
270 o = offset & (PAGE_SIZE-1); 284 page_offset = offset & (PAGE_SIZE-1);
271 l = remain; 285 page_length = remain;
272 if ((o + l) > PAGE_SIZE) 286 if ((page_offset + remain) > PAGE_SIZE)
273 l = PAGE_SIZE - o; 287 page_length = PAGE_SIZE - page_offset;
274 288
275 pfn = (dev->agp->base >> PAGE_SHIFT) + i; 289 ret = fast_user_write (dev_priv->mm.gtt_mapping, page_base,
276 290 page_offset, user_data, page_length);
277 if (!fast_user_write(pfn, user_data, l, o)) { 291
278 unsigned long unwritten; 292 /* If we get a fault while copying data, then (presumably) our
279 char __iomem *vaddr; 293 * source page isn't available. In this case, use the
280 294 * non-atomic function
281 vaddr = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE); 295 */
282#if WATCH_PWRITE 296 if (ret) {
283 DRM_INFO("pwrite slow i %d o %d l %d " 297 ret = slow_user_write (dev_priv->mm.gtt_mapping,
284 "pfn %ld vaddr %p\n", 298 page_base, page_offset,
285 i, o, l, pfn, vaddr); 299 user_data, page_length);
286#endif 300 if (ret)
287 if (vaddr == NULL) {
288 ret = -EFAULT;
289 goto fail;
290 }
291 unwritten = __copy_from_user(vaddr + o, user_data, l);
292#if WATCH_PWRITE
293 DRM_INFO("unwritten %ld\n", unwritten);
294#endif
295 iounmap(vaddr);
296 if (unwritten) {
297 ret = -EFAULT;
298 goto fail; 301 goto fail;
299 }
300 } 302 }
301 303
302 remain -= l; 304 remain -= page_length;
303 user_data += l; 305 user_data += page_length;
304 offset += l; 306 offset += page_length;
305 } 307 }
306#if WATCH_PWRITE && 1
307 i915_gem_clflush_object(obj);
308 i915_gem_dump_object(obj, args->offset + args->size, __func__, ~0);
309 i915_gem_clflush_object(obj);
310#endif
311 308
312fail: 309fail:
313 i915_gem_object_unpin(obj); 310 i915_gem_object_unpin(obj);
@@ -1525,12 +1522,12 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
1525 struct drm_i915_gem_exec_object *entry) 1522 struct drm_i915_gem_exec_object *entry)
1526{ 1523{
1527 struct drm_device *dev = obj->dev; 1524 struct drm_device *dev = obj->dev;
1525 drm_i915_private_t *dev_priv = dev->dev_private;
1528 struct drm_i915_gem_relocation_entry reloc; 1526 struct drm_i915_gem_relocation_entry reloc;
1529 struct drm_i915_gem_relocation_entry __user *relocs; 1527 struct drm_i915_gem_relocation_entry __user *relocs;
1530 struct drm_i915_gem_object *obj_priv = obj->driver_private; 1528 struct drm_i915_gem_object *obj_priv = obj->driver_private;
1531 int i, ret; 1529 int i, ret;
1532 uint32_t last_reloc_offset = -1; 1530 void __iomem *reloc_page;
1533 void __iomem *reloc_page = NULL;
1534 1531
1535 /* Choose the GTT offset for our buffer and put it there. */ 1532 /* Choose the GTT offset for our buffer and put it there. */
1536 ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment); 1533 ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
@@ -1653,26 +1650,11 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
1653 * perform. 1650 * perform.
1654 */ 1651 */
1655 reloc_offset = obj_priv->gtt_offset + reloc.offset; 1652 reloc_offset = obj_priv->gtt_offset + reloc.offset;
1656 if (reloc_page == NULL || 1653 reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
1657 (last_reloc_offset & ~(PAGE_SIZE - 1)) != 1654 (reloc_offset &
1658 (reloc_offset & ~(PAGE_SIZE - 1))) { 1655 ~(PAGE_SIZE - 1)));
1659 if (reloc_page != NULL)
1660 iounmap(reloc_page);
1661
1662 reloc_page = ioremap_wc(dev->agp->base +
1663 (reloc_offset &
1664 ~(PAGE_SIZE - 1)),
1665 PAGE_SIZE);
1666 last_reloc_offset = reloc_offset;
1667 if (reloc_page == NULL) {
1668 drm_gem_object_unreference(target_obj);
1669 i915_gem_object_unpin(obj);
1670 return -ENOMEM;
1671 }
1672 }
1673
1674 reloc_entry = (uint32_t __iomem *)(reloc_page + 1656 reloc_entry = (uint32_t __iomem *)(reloc_page +
1675 (reloc_offset & (PAGE_SIZE - 1))); 1657 (reloc_offset & (PAGE_SIZE - 1)));
1676 reloc_val = target_obj_priv->gtt_offset + reloc.delta; 1658 reloc_val = target_obj_priv->gtt_offset + reloc.delta;
1677 1659
1678#if WATCH_BUF 1660#if WATCH_BUF
@@ -1681,6 +1663,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
1681 readl(reloc_entry), reloc_val); 1663 readl(reloc_entry), reloc_val);
1682#endif 1664#endif
1683 writel(reloc_val, reloc_entry); 1665 writel(reloc_val, reloc_entry);
1666 io_mapping_unmap_atomic(reloc_page);
1684 1667
1685 /* Write the updated presumed offset for this entry back out 1668 /* Write the updated presumed offset for this entry back out
1686 * to the user. 1669 * to the user.
@@ -1696,9 +1679,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
1696 drm_gem_object_unreference(target_obj); 1679 drm_gem_object_unreference(target_obj);
1697 } 1680 }
1698 1681
1699 if (reloc_page != NULL)
1700 iounmap(reloc_page);
1701
1702#if WATCH_BUF 1682#if WATCH_BUF
1703 if (0) 1683 if (0)
1704 i915_gem_dump_object(obj, 128, __func__, ~0); 1684 i915_gem_dump_object(obj, 128, __func__, ~0);
@@ -2540,6 +2520,10 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
2540 if (ret != 0) 2520 if (ret != 0)
2541 return ret; 2521 return ret;
2542 2522
2523 dev_priv->mm.gtt_mapping = io_mapping_create_wc(dev->agp->base,
2524 dev->agp->agp_info.aper_size
2525 * 1024 * 1024);
2526
2543 mutex_lock(&dev->struct_mutex); 2527 mutex_lock(&dev->struct_mutex);
2544 BUG_ON(!list_empty(&dev_priv->mm.active_list)); 2528 BUG_ON(!list_empty(&dev_priv->mm.active_list));
2545 BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); 2529 BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
@@ -2557,11 +2541,13 @@ int
2557i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, 2541i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
2558 struct drm_file *file_priv) 2542 struct drm_file *file_priv)
2559{ 2543{
2544 drm_i915_private_t *dev_priv = dev->dev_private;
2560 int ret; 2545 int ret;
2561 2546
2562 ret = i915_gem_idle(dev); 2547 ret = i915_gem_idle(dev);
2563 drm_irq_uninstall(dev); 2548 drm_irq_uninstall(dev);
2564 2549
2550 io_mapping_free(dev_priv->mm.gtt_mapping);
2565 return ret; 2551 return ret;
2566} 2552}
2567 2553