diff options
author | Dave Airlie <airlied@redhat.com> | 2012-02-14 14:16:00 +0000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-02-14 14:16:00 +0000 |
commit | cdbe8b5426e71d09882212073c27c9dcf25a71b6 (patch) | |
tree | 5ff82cebd1875ac91f64f337388c8845bcbc69e8 | |
parent | 285484e2d55e76031b45926720c10b1aec8b782a (diff) | |
parent | 172975aa746e155533cb386c7159c2d6510e2bc8 (diff) |
Merge tag 'drm-intel-next-2012-02-07' of git://people.freedesktop.org/~danvet/drm-intel into drm-core-next
* tag 'drm-intel-next-2012-02-07' of git://people.freedesktop.org/~danvet/drm-intel: (29 commits)
drm/i915: Handle unmappable buffers during error state capture
drm/i915: rewrite shmem_pread_slow to use copy_to_user
drm/i915: rewrite shmem_pwrite_slow to use copy_from_user
drm/i915: fall through pwrite_gtt_slow to the shmem slow path
drm/i915: add debugfs file for swizzling information
drm/i915: fix swizzle detection for gen3
drm/i915: Remove the upper limit on the bo size for mapping into the CPU domain
drm/i915: add per-ring fault reg to error_state
drm/i915: reject GTT domain in relocations
drm/i915: remove the i915_batchbuffer_info debugfs file
drm/i915: capture error_state also for stuck rings
drm/i915: refactor debugfs create functions
drm/i915: refactor debugfs open function
drm/i915: don't trash the gtt when running out of fences
drm/i915: Separate fence pin counting from normal bind pin counting
drm/i915/ringbuffer: kill snb blt workaround
drm/i915: collect more per ring error state
drm/i915: refactor ring error state capture to use arrays
drm/i915: switch ring->id to be a real id
drm/i915: set AUD_CONFIG N_value_index for DisplayPort
...
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 241 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 53 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 394 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_evict.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 150 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_tiling.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 116 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 57 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_overlay.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 97 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.h | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 4 |
16 files changed, 575 insertions, 604 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9717bf42f84..11ae06aac1f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -564,45 +564,6 @@ static int i915_hws_info(struct seq_file *m, void *data) return 0; } -static void i915_dump_object(struct seq_file *m, - struct io_mapping *mapping, - struct drm_i915_gem_object *obj) -{ - int page, page_count, i; - - page_count = obj->base.size / PAGE_SIZE; - for (page = 0; page < page_count; page++) { - u32 *mem = io_mapping_map_wc(mapping, - obj->gtt_offset + page * PAGE_SIZE); - for (i = 0; i < PAGE_SIZE; i += 4) - seq_printf(m, "%08x : %08x\n", i, mem[i / 4]); - io_mapping_unmap(mem); - } -} - -static int i915_batchbuffer_info(struct seq_file *m, void *data) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj; - int ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; - - list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { - if (obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) { - seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset); - i915_dump_object(m, dev_priv->mm.gtt_mapping, obj); - } - } - - mutex_unlock(&dev->struct_mutex); - return 0; -} - static int i915_ringbuffer_data(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -669,9 +630,9 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) static const char *ring_str(int ring) { switch (ring) { - case RING_RENDER: return " render"; - case RING_BSD: return " bsd"; - case RING_BLT: return " blt"; + case RCS: return "render"; + case VCS: return "bsd"; + case BCS: return "blt"; default: return ""; } } @@ -714,7 +675,7 @@ static void print_error_buffers(struct seq_file *m, seq_printf(m, "%s [%d]:\n", name, count); while (count--) { - seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s", + seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s%s", err->gtt_offset, err->size, err->read_domains, @@ -724,6 +685,7 @@ static void print_error_buffers(struct seq_file *m, tiling_flag(err->tiling), dirty_flag(err->dirty), purgeable_flag(err->purgeable), + err->ring != -1 ? " " : "", ring_str(err->ring), cache_level_str(err->cache_level)); @@ -737,6 +699,32 @@ static void print_error_buffers(struct seq_file *m, } } +static void i915_ring_error_state(struct seq_file *m, + struct drm_device *dev, + struct drm_i915_error_state *error, + unsigned ring) +{ + seq_printf(m, "%s command stream:\n", ring_str(ring)); + seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]); + seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); + seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); + seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); + seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); + seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); + if (ring == RCS && INTEL_INFO(dev)->gen >= 4) { + seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); + seq_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); + } + if (INTEL_INFO(dev)->gen >= 4) + seq_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); + seq_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); + if (INTEL_INFO(dev)->gen >= 6) { + seq_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); + seq_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); + } + seq_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); +} + static int i915_error_state(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -759,35 +747,20 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); seq_printf(m, "EIR: 0x%08x\n", error->eir); seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); + + for (i = 0; i < dev_priv->num_fence_regs; i++) + seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); + if (INTEL_INFO(dev)->gen >= 6) { seq_printf(m, "ERROR: 0x%08x\n", error->error); - seq_printf(m, "Blitter command stream:\n"); - seq_printf(m, " ACTHD: 0x%08x\n", error->bcs_acthd); - seq_printf(m, " IPEIR: 0x%08x\n", error->bcs_ipeir); - seq_printf(m, " IPEHR: 0x%08x\n", error->bcs_ipehr); - seq_printf(m, " INSTDONE: 0x%08x\n", error->bcs_instdone); - seq_printf(m, " seqno: 0x%08x\n", error->bcs_seqno); - seq_printf(m, "Video (BSD) command stream:\n"); - seq_printf(m, " ACTHD: 0x%08x\n", error->vcs_acthd); - seq_printf(m, " IPEIR: 0x%08x\n", error->vcs_ipeir); - seq_printf(m, " IPEHR: 0x%08x\n", error->vcs_ipehr); - seq_printf(m, " INSTDONE: 0x%08x\n", error->vcs_instdone); - seq_printf(m, " seqno: 0x%08x\n", error->vcs_seqno); + seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); } - seq_printf(m, "Render command stream:\n"); - seq_printf(m, " ACTHD: 0x%08x\n", error->acthd); - seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir); - seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr); - seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone); - if (INTEL_INFO(dev)->gen >= 4) { - seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); - seq_printf(m, " INSTPS: 0x%08x\n", error->instps); - } - seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); - seq_printf(m, " seqno: 0x%08x\n", error->seqno); - for (i = 0; i < dev_priv->num_fence_regs; i++) - seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); + i915_ring_error_state(m, dev, error, RCS); + if (HAS_BLT(dev)) + i915_ring_error_state(m, dev, error, BCS); + if (HAS_BSD(dev)) + i915_ring_error_state(m, dev, error, VCS); if (error->active_bo) print_error_buffers(m, "Active", @@ -1415,9 +1388,58 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data) return 0; } +static const char *swizzle_string(unsigned swizzle) +{ + switch(swizzle) { + case I915_BIT_6_SWIZZLE_NONE: + return "none"; + case I915_BIT_6_SWIZZLE_9: + return "bit9"; + case I915_BIT_6_SWIZZLE_9_10: + return "bit9/bit10"; + case I915_BIT_6_SWIZZLE_9_11: + return "bit9/bit11"; + case I915_BIT_6_SWIZZLE_9_10_11: + return "bit9/bit10/bit11"; + case I915_BIT_6_SWIZZLE_9_17: + return "bit9/bit17"; + case I915_BIT_6_SWIZZLE_9_10_17: + return "bit9/bit10/bit17"; + case I915_BIT_6_SWIZZLE_UNKNOWN: + return "unkown"; + } + + return "bug"; +} + +static int i915_swizzle_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev->struct_mutex); + seq_printf(m, "bit6 swizzle for X-tiling = %s\n", + swizzle_string(dev_priv->mm.bit_6_swizzle_x)); + seq_printf(m, "bit6 swizzle for Y-tiling = %s\n", + swizzle_string(dev_priv->mm.bit_6_swizzle_y)); + + if (IS_GEN3(dev) || IS_GEN4(dev)) { + seq_printf(m, "DDC = 0x%08x\n", + I915_READ(DCC)); + seq_printf(m, "C0DRB3 = 0x%04x\n", + I915_READ16(C0DRB3)); + seq_printf(m, "C1DRB3 = 0x%04x\n", + I915_READ16(C1DRB3)); + } + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int -i915_wedged_open(struct inode *inode, - struct file *filp) +i915_debugfs_common_open(struct inode *inode, + struct file *filp) { filp->private_data = inode->i_private; return 0; @@ -1473,20 +1495,12 @@ i915_wedged_write(struct file *filp, static const struct file_operations i915_wedged_fops = { .owner = THIS_MODULE, - .open = i915_wedged_open, + .open = i915_debugfs_common_open, .read = i915_wedged_read, .write = i915_wedged_write, .llseek = default_llseek, }; -static int -i915_max_freq_open(struct inode *inode, - struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - static ssize_t i915_max_freq_read(struct file *filp, char __user *ubuf, @@ -1543,20 +1557,12 @@ i915_max_freq_write(struct file *filp, static const struct file_operations i915_max_freq_fops = { .owner = THIS_MODULE, - .open = i915_max_freq_open, + .open = i915_debugfs_common_open, .read = i915_max_freq_read, .write = i915_max_freq_write, .llseek = default_llseek, }; -static int -i915_cache_sharing_open(struct inode *inode, - struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - static ssize_t i915_cache_sharing_read(struct file *filp, char __user *ubuf, @@ -1622,7 +1628,7 @@ i915_cache_sharing_write(struct file *filp, static const struct file_operations i915_cache_sharing_fops = { .owner = THIS_MODULE, - .open = i915_cache_sharing_open, + .open = i915_debugfs_common_open, .read = i915_cache_sharing_read, .write = i915_cache_sharing_write, .llseek = default_llseek, @@ -1654,21 +1660,6 @@ drm_add_fake_info_node(struct drm_minor *minor, return 0; } -static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) -{ - struct drm_device *dev = minor->dev; - struct dentry *ent; - - ent = debugfs_create_file("i915_wedged", - S_IRUGO | S_IWUSR, - root, dev, - &i915_wedged_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); - - return drm_add_fake_info_node(minor, ent, &i915_wedged_fops); -} - static int i915_forcewake_open(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; @@ -1730,34 +1721,22 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops); } -static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor) -{ - struct drm_device *dev = minor->dev; - struct dentry *ent; - - ent = debugfs_create_file("i915_max_freq", - S_IRUGO | S_IWUSR, - root, dev, - &i915_max_freq_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); - - return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops); -} - -static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor) +static int i915_debugfs_create(struct dentry *root, + struct drm_minor *minor, + const char *name, + const struct file_operations *fops) { struct drm_device *dev = minor->dev; struct dentry *ent; - ent = debugfs_create_file("i915_cache_sharing", + ent = debugfs_create_file(name, S_IRUGO | S_IWUSR, root, dev, - &i915_cache_sharing_fops); + fops); if (IS_ERR(ent)) return PTR_ERR(ent); - return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops); + return drm_add_fake_info_node(minor, ent, fops); } static struct drm_info_list i915_debugfs_list[] = { @@ -1783,7 +1762,6 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS}, {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS}, {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS}, - {"i915_batchbuffers", i915_batchbuffer_info, 0}, {"i915_error_state", i915_error_state, 0}, {"i915_rstdby_delays", i915_rstdby_delays, 0}, {"i915_cur_delayinfo", i915_cur_delayinfo, 0}, @@ -1799,6 +1777,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_context_status", i915_context_status, 0}, {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0}, + {"i915_swizzle_info", i915_swizzle_info, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) @@ -1806,17 +1785,25 @@ int i915_debugfs_init(struct drm_minor *minor) { int ret; - ret = i915_wedged_create(minor->debugfs_root, minor); + ret = i915_debugfs_create(minor->debugfs_root, minor, + "i915_wedged", + &i915_wedged_fops); if (ret) return ret; ret = i915_forcewake_create(minor->debugfs_root, minor); if (ret) return ret; - ret = i915_max_freq_create(minor->debugfs_root, minor); + + ret = i915_debugfs_create(minor->debugfs_root, minor, + "i915_max_freq", + &i915_max_freq_fops); if (ret) return ret; - ret = i915_cache_sharing_create(minor->debugfs_root, minor); + + ret = i915_debugfs_create(minor->debugfs_root, minor, + "i915_cache_sharing", + &i915_cache_sharing_fops); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 448848cbc1d..8919dcc07ed 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2132,7 +2132,7 @@ int i915_driver_unload(struct drm_device *dev) unregister_shrinker(&dev_priv->mm.inactive_shrinker); mutex_lock(&dev->struct_mutex); - ret = i915_gpu_idle(dev); + ret = i915_gpu_idle(dev, true); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 32737a37edd..68a5338ea86 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -135,6 +135,7 @@ struct drm_i915_fence_reg { struct list_head lru_list; struct drm_i915_gem_object *obj; uint32_t setup_seqno; + int pin_count; }; struct sdvo_device_mapping { @@ -152,26 +153,21 @@ struct drm_i915_error_state { u32 eir; u32 pgtbl_er; u32 pipestat[I915_MAX_PIPES]; - u32 ipeir; - u32 ipehr; - u32 instdone; - u32 acthd; + u32 tail[I915_NUM_RINGS]; + u32 head[I915_NUM_RINGS]; + u32 ipeir[I915_NUM_RINGS]; + u32 ipehr[I915_NUM_RINGS]; + u32 instdone[I915_NUM_RINGS]; + u32 acthd[I915_NUM_RINGS]; u32 error; /* gen6+ */ - u32 bcs_acthd; /* gen6+ blt engine */ - u32 bcs_ipehr; - u32 bcs_ipeir; - u32 bcs_instdone; - u32 bcs_seqno; - u32 vcs_acthd; /* gen6+ bsd engine */ - u32 vcs_ipehr; - u32 vcs_ipeir; - u32 vcs_instdone; - u32 vcs_seqno; - u32 instpm; - u32 instps; + u32 instpm[I915_NUM_RINGS]; + u32 instps[I915_NUM_RINGS]; u32 instdone1; - u32 seqno; + u32 seqno[I915_NUM_RINGS]; u64 bbaddr; + u32 fault_reg[I915_NUM_RINGS]; + u32 done_reg; + u32 faddr[I915_NUM_RINGS]; u64 fence[I915_MAX_NUM_FENCES]; struct timeval time; struct drm_i915_error_object { @@ -1170,6 +1166,24 @@ int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj, struct intel_ring_buffer *pipelined); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); +static inline void +i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) +{ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + dev_priv->fence_regs[obj->fence_reg].pin_count++; + } +} + +static inline void +i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) +{ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + dev_priv->fence_regs[obj->fence_reg].pin_count--; + } +} + void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_reset(struct drm_device *dev); void i915_gem_clflush_object(struct drm_i915_gem_object *obj); @@ -1183,13 +1197,14 @@ void i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end); -int __must_check i915_gpu_idle(struct drm_device *dev); +int __must_check i915_gpu_idle(struct drm_device *dev, bool do_retire); int __must_check i915_gem_idle(struct drm_device *dev); int __must_check i915_add_request(struct intel_ring_buffer *ring, struct drm_file *file, struct drm_i915_gem_request *request); int __must_check i915_wait_request(struct intel_ring_buffer *ring, - uint32_t seqno); + uint32_t seqno, + bool do_retire); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int __must_check i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index eb98a7f55cf..51a2b0c2a30 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -58,6 +58,7 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj); static int i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc); +static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); /* some bookkeeping */ static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, @@ -258,73 +259,6 @@ static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) obj->tiling_mode != I915_TILING_NONE; } -static inline void -slow_shmem_copy(struct page *dst_page, - int dst_offset, - struct page *src_page, - int src_offset, - int length) -{ - char *dst_vaddr, *src_vaddr; - - dst_vaddr = kmap(dst_page); - src_vaddr = kmap(src_page); - - memcpy(dst_vaddr + dst_offset, src_vaddr + src_offset, length); - - kunmap(src_page); - kunmap(dst_page); -} - -static inline void -slow_shmem_bit17_copy(struct page *gpu_page, - int gpu_offset, - struct page *cpu_page, - int cpu_offset, - int length, - int is_read) -{ - char *gpu_vaddr, *cpu_vaddr; - - /* Use the unswizzled path if this page isn't affected. */ - if ((page_to_phys(gpu_page) & (1 << 17)) == 0) { - if (is_read) - return slow_shmem_copy(cpu_page, cpu_offset, - gpu_page, gpu_offset, length); - else - return slow_shmem_copy(gpu_page, gpu_offset, - cpu_page, cpu_offset, length); - } - - gpu_vaddr = kmap(gpu_page); - cpu_vaddr = kmap(cpu_page); - - /* Copy the data, XORing A6 with A17 (1). The user already knows he's - * XORing with the other bits (A9 for Y, A9 and A10 for X) - */ - while (length > 0) { - int cacheline_end = ALIGN(gpu_offset + 1, 64); - int this_length = min(cacheline_end - gpu_offset, length); - int swizzled_gpu_offset = gpu_offset ^ 64; - - if (is_read) { - memcpy(cpu_vaddr + cpu_offset, - gpu_vaddr + swizzled_gpu_offset, - this_length); - } else { - memcpy(gpu_vaddr + swizzled_gpu_offset, - cpu_vaddr + cpu_offset, - this_length); - } - cpu_offset += this_length; - gpu_offset += this_length; - length -= this_length; - } - - kunmap(cpu_page); - kunmap(gpu_page); -} - /** * This is the fast shmem pread path, which attempts to copy_from_user directly * from the backing pages of the object to the user's address space. On a @@ -385,6 +319,58 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, return 0; } +static inline int +__copy_to_user_swizzled(char __user *cpu_vaddr, + const char *gpu_vaddr, int gpu_offset, + int length) +{ + int ret, cpu_offset = 0; + + while (length > 0) { + int cacheline_end = ALIGN(gpu_offset + 1, 64); + int this_length = min(cacheline_end - gpu_offset, length); + int swizzled_gpu_offset = gpu_offset ^ 64; + + ret = __copy_to_user(cpu_vaddr + cpu_offset, + gpu_vaddr + swizzled_gpu_offset, + this_length); + if (ret) + return ret + length; + + cpu_offset += this_length; + gpu_offset += this_length; + length -= this_length; + } + + return 0; +} + +static inline int +__copy_from_user_swizzled(char __user *gpu_vaddr, int gpu_offset, + const char *cpu_vaddr, + int length) +{ + int ret, cpu_offset = 0; + + while (length > 0) { + int cacheline_end = ALIGN(gpu_offset + 1, 64); + int this_length = min(cacheline_end - gpu_offset, length); + int swizzled_gpu_offset = gpu_offset ^ 64; + + ret = __copy_from_user(gpu_vaddr + swizzled_gpu_offset, + cpu_vaddr + cpu_offset, + this_length); + if (ret) + return ret + length; + + cpu_offset += this_length; + gpu_offset += this_length; + length -= this_length; + } + + return 0; +} + /** * This is the fallback shmem pread path, which allocates temporary storage * in kernel space to copy_to_user into outside of the struct_mutex, so we @@ -398,72 +384,34 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_file *file) { struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; - struct mm_struct *mm = current->mm; - struct page **user_pages; + char __user *user_data; ssize_t remain; - loff_t offset, pinned_pages, i; - loff_t first_data_page, last_data_page, num_pages; - int shmem_page_offset; - int data_page_index, data_page_offset; - int page_length; - int ret; - uint64_t data_ptr = args->data_ptr; - int do_bit17_swizzling; + loff_t offset; + int shmem_page_offset, page_length, ret; + int obj_do_bit17_swizzling, page_do_bit17_swizzling; + user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - /* Pin the user pages containing the data. We can't fault while - * holding the struct mutex, yet we want to hold it while - * dereferencing the user data. - */ - first_data_page = data_ptr / PAGE_SIZE; - last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; - num_pages = last_data_page - first_data_page + 1; + obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - user_pages = drm_malloc_ab(num_pages, sizeof(struct page *)); - if (user_pages == NULL) - return -ENOMEM; + offset = args->offset; mutex_unlock(&dev->struct_mutex); - down_read(&mm->mmap_sem); - pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, - num_pages, 1, 0, user_pages, NULL); - up_read(&mm->mmap_sem); - mutex_lock(&dev->struct_mutex); - if (pinned_pages < num_pages) { - ret = -EFAULT; - goto out; - } - - ret = i915_gem_object_set_cpu_read_domain_range(obj, - args->offset, - args->size); - if (ret) - goto out; - - do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - - offset = args->offset; while (remain > 0) { struct page *page; + char *vaddr; /* Operation in this page * * shmem_page_offset = offset within page in shmem file - * data_page_index = page number in get_user_pages return - * data_page_offset = offset with data_page_index page. * page_length = bytes to copy for this page */ shmem_page_offset = offset_in_page(offset); - data_page_index = data_ptr / PAGE_SIZE - first_data_page; - data_page_offset = offset_in_page(data_ptr); - page_length = remain; if ((shmem_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - shmem_page_offset; - if ((data_page_offset + page_length) > PAGE_SIZE) - page_length = PAGE_SIZE - data_page_offset; page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); if (IS_ERR(page)) { @@ -471,36 +419,38 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, goto out; } - if (do_bit17_swizzling) { - slow_shmem_bit17_copy(page, - shmem_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length, - 1); - } else { - slow_shmem_copy(user_pages[data_page_index], - data_page_offset, - page, - shmem_page_offset, - page_length); - } + page_do_bit17_swizzling = obj_do_bit17_swizzling && + (page_to_phys(page) & (1 << 17)) != 0; + + vaddr = kmap(page); + if (page_do_bit17_swizzling) + ret = __copy_to_user_swizzled(user_data, + vaddr, shmem_page_offset, + page_length); + else + ret = __copy_to_user(user_data, + vaddr + shmem_page_offset, + page_length); + kunmap(page); mark_page_accessed(page); page_cache_release(page); + if (ret) { + ret = -EFAULT; + goto out; + } + remain -= page_length; - data_ptr += page_length; + user_data += page_length; offset += page_length; } out: - for (i = 0; i < pinned_pages; i++) { - SetPageDirty(user_pages[i]); - mark_page_accessed(user_pages[i]); - page_cache_release(user_pages[i]); - } - drm_free_large(user_pages); + mutex_lock(&dev->struct_mutex); + /* Fixup: Kill any reinstated backing storage pages */ + if (obj->madv == __I915_MADV_PURGED) + i915_gem_object_truncate(obj); return ret; } @@ -841,71 +791,36 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_file *file) { struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; - struct mm_struct *mm = current->mm; - struct page **user_pages; ssize_t remain; - loff_t offset, pinned_pages, i; - loff_t first_data_page, last_data_page, num_pages; - int shmem_page_offset; - int data_page_index, data_page_offset; - int page_length; - int ret; - uint64_t data_ptr = args->data_ptr; - int do_bit17_swizzling; + loff_t offset; + char __user *user_data; + int shmem_page_offset, page_length, ret; + int obj_do_bit17_swizzling, page_do_bit17_swizzling; + user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - /* Pin the user pages containing the data. We can't fault while - * holding the struct mutex, and all of the pwrite implementations - * want to hold it while dereferencing the user data. - */ - first_data_page = data_ptr / PAGE_SIZE; - last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; - num_pages = last_data_page - first_data_page + 1; - - user_pages = drm_malloc_ab(num_pages, sizeof(struct page *)); - if (user_pages == NULL) - return -ENOMEM; - - mutex_unlock(&dev->struct_mutex); - down_read(&mm->mmap_sem); - pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, - num_pages, 0, 0, user_pages, NULL); - up_read(&mm->mmap_sem); - mutex_lock(&dev->struct_mutex); - if (pinned_pages < num_pages) { - ret = -EFAULT; - goto out; - } - - ret = i915_gem_object_set_to_cpu_domain(obj, 1); - if (ret) - goto out; - - do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); + obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); offset = args->offset; obj->dirty = 1; + mutex_unlock(&dev->struct_mutex); + while (remain > 0) { struct page *page; + char *vaddr; /* Operation in this page * * shmem_page_offset = offset within page in shmem file - * data_page_index = page number in get_user_pages return - * data_page_offset = offset with data_page_index page. * page_length = bytes to copy for this page */ shmem_page_offset = offset_in_page(offset); - data_page_index = data_ptr / PAGE_SIZE - first_data_page; - data_page_offset = offset_in_page(data_ptr); page_length = remain; if ((shmem_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - shmem_page_offset; - if ((data_page_offset + page_length) > PAGE_SIZE) - page_length = PAGE_SIZE - data_page_offset; page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); if (IS_ERR(page)) { @@ -913,34 +828,45 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, goto out; } - if (do_bit17_swizzling) { - slow_shmem_bit17_copy(page, - shmem_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length, - 0); - } else { - slow_shmem_copy(page, - shmem_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length); - } + page_do_bit17_swizzling = obj_do_bit17_swizzling && + (page_to_phys(page) & (1 << 17)) != 0; + + vaddr = kmap(page); + if (page_do_bit17_swizzling) + ret = __copy_from_user_swizzled(vaddr, shmem_page_offset, + user_data, + page_length); + else + ret = __copy_from_user(vaddr + shmem_page_offset, + user_data, + page_length); + kunmap(page); set_page_dirty(page); mark_page_accessed(page); page_cache_release(page); + if (ret) { + ret = -EFAULT; + goto out; + } + remain -= page_length; - data_ptr += page_length; + user_data += page_length; offset += page_length; } out: - for (i = 0; i < pinned_pages; i++) - page_cache_release(user_pages[i]); - drm_free_large(user_pages); + mutex_lock(&dev->struct_mutex); + /* Fixup: Kill any reinstated backing storage pages */ + if (obj->madv == __I915_MADV_PURGED) + i915_gem_object_truncate(obj); + /* and flush dirty cachelines in case the object isn't in the cpu write + * domain anymore. */ + if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) { + i915_gem_clflush_object(obj); + intel_gtt_chipset_flush(); + } return ret; } @@ -996,10 +922,13 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, * pread/pwrite currently are reading and writing from the CPU * perspective, requiring manual detiling by the client. */ - if (obj->phys_obj) + if (obj->phys_obj) { ret = i915_gem_phys_pwrite(dev, obj, args, file); - else if (obj->gtt_space && - obj->base.write_domain != I915_GEM_DOMAIN_CPU) { + goto out; + } + + if (obj->gtt_space && + obj->base.write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_object_pin(obj, 0, true); if (ret) goto out; @@ -1018,18 +947,24 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, out_unpin: i915_gem_object_unpin(obj); - } else { - ret = i915_gem_object_set_to_cpu_domain(obj, 1); - if (ret) - goto out; - ret = -EFAULT; - if (!i915_gem_object_needs_bit17_swizzle(obj)) - ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file); - if (ret == -EFAULT) |