diff options
Diffstat (limited to 'shared-core')
-rw-r--r-- | shared-core/i915_dma.c | 1 | ||||
-rw-r--r-- | shared-core/i915_drm.h | 9 | ||||
-rw-r--r-- | shared-core/i915_drv.h | 49 | ||||
-rw-r--r-- | shared-core/i915_irq.c | 188 |
4 files changed, 132 insertions, 115 deletions
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 5a94c156..09c53676 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1093,6 +1093,7 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index d9ce2484..8ba71687 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -189,6 +189,7 @@ typedef struct drm_i915_sarea { #define DRM_I915_GEM_PWRITE 0x1d #define DRM_I915_GEM_MMAP 0x1e #define DRM_I915_GEM_SET_DOMAIN 0x1f +#define DRM_I915_GEM_SW_FINISH 0x20 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -221,6 +222,7 @@ typedef struct drm_i915_sarea { #define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) #define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) #define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain) +#define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish) /* Asynchronous page flipping: */ @@ -505,6 +507,11 @@ struct drm_i915_gem_set_domain { uint32_t write_domain; }; +struct drm_i915_gem_sw_finish { + /** Handle for the object */ + uint32_t handle; +}; + struct drm_i915_gem_relocation_entry { /** * Handle of the buffer being pointed to by this relocation entry. @@ -569,6 +576,8 @@ struct drm_i915_gem_relocation_entry { #define I915_GEM_DOMAIN_INSTRUCTION 0x00000010 /** Vertex address cache */ #define I915_GEM_DOMAIN_VERTEX 0x00000020 +/** GTT domain - aperture and scanout */ +#define I915_GEM_DOMAIN_GTT 0x00000040 /** @} */ struct drm_i915_gem_exec_object { diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index ee5e9dfd..17829a56 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -134,7 +134,6 @@ struct drm_i915_private { wait_queue_head_t irq_queue; atomic_t irq_received; - atomic_t irq_emitted; int tex_lru_log_granularity; int allow_batchbuffer; @@ -235,15 +234,34 @@ struct drm_i915_private { uint32_t next_gem_seqno; - /** - * Flag if the X Server, and thus DRM, is not currently in - * control of the device. - * - * This is set between LeaveVT and EnterVT. It needs to be - * replaced with a semaphore. It also needs to be - * transitioned away from for kernel modesetting. - */ - int suspended; + /** + * Waiting sequence number, if any + */ + uint32_t waiting_gem_seqno; + + /** + * Last seq seen at irq time + */ + uint32_t irq_gem_seqno; + + /** + * Flag if the X Server, and thus DRM, is not currently in + * control of the device. + * + * This is set between LeaveVT and EnterVT. It needs to be + * replaced with a semaphore. It also needs to be + * transitioned away from for kernel modesetting. + */ + int suspended; + + /** + * Flag if the hardware appears to be wedged. + * + * This is set when attempts to idle the device timeout. + * It prevents command submission from occuring and makes + * every pending request fail + */ + int wedged; } mm; struct work_struct user_interrupt_task; @@ -369,6 +387,12 @@ struct drm_i915_gem_object { */ int active; + /** + * This is set if the object has been written to since last bound + * to the GTT + */ + int dirty; + /** AGP memory structure for our GTT binding. */ DRM_AGP_MEM *agp_mem; @@ -521,6 +545,8 @@ int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_pin_ioctl(struct drm_device *dev, void *data, @@ -535,11 +561,14 @@ int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int i915_gem_proc_init(struct drm_minor *minor); +void i915_gem_proc_cleanup(struct drm_minor *minor); int i915_gem_init_object(struct drm_gem_object *obj); void i915_gem_free_object(struct drm_gem_object *obj); int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment); void i915_gem_object_unpin(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); +uint32_t i915_get_gem_seqno(struct drm_device *dev); void i915_gem_retire_requests(struct drm_device *dev); int i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 0dea6e56..bad5ae29 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -42,6 +42,26 @@ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) +static inline void +i915_enable_irq(struct drm_i915_private *dev_priv, uint32_t mask) +{ + if ((dev_priv->irq_mask_reg & mask) != 0) { + dev_priv->irq_mask_reg &= ~mask; + I915_WRITE(IMR, dev_priv->irq_mask_reg); + (void) I915_READ(IMR); + } +} + +static inline void +i915_disable_irq(struct drm_i915_private *dev_priv, uint32_t mask) +{ + if ((dev_priv->irq_mask_reg & mask) != mask) { + dev_priv->irq_mask_reg |= mask; + I915_WRITE(IMR, dev_priv->irq_mask_reg); + (void) I915_READ(IMR); + } +} + /** * i915_get_pipe - return the the pipe associated with a given plane * @dev: DRM device @@ -510,17 +530,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) int hotplug = 0; int vblank = 0; - /* On i8xx/i915 hw the IIR and IER are 16bit on i9xx its 32bit */ - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - iir = I915_READ(IIR); - else - iir = I915_READ16(IIR); - if (dev->pdev->msi_enabled) - I915_WRITE(IER, 0); - - if (!iir) + I915_WRITE(IMR, ~0); + iir = I915_READ(IIR); +#if 0 + DRM_DEBUG("flag=%08x\n", iir); +#endif + atomic_inc(&dev_priv->irq_received); + if (iir == 0) { + DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", + iir, + I915_READ(IMR), + I915_READ(IER), + I915_READ(PIPEASTAT), + I915_READ(PIPEBSTAT)); + if (dev->pdev->msi_enabled) { + I915_WRITE(IMR, + dev_priv->irq_mask_reg); + (void) I915_READ(IMR); + } return IRQ_NONE; + } /* * Clear the PIPE(A|B)STAT regs before the IIR otherwise @@ -528,46 +558,29 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) */ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { pipea_stats = I915_READ(PIPEASTAT); - if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| - PIPE_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 0)); - } - - /* This is a global event, and not a pipe A event */ - if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS) - hotplug = 1; - - if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS) { - hotplug = 1; - /* Toggle hotplug detection to clear hotplug status */ - tvdac = I915_READ(TV_DAC); - I915_WRITE(TV_DAC, tvdac & ~TVDAC_STATE_CHG_EN); - I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN); - } - I915_WRITE(PIPEASTAT, pipea_stats); } if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { pipeb_stats = I915_READ(PIPEBSTAT); - if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| - PIPE_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 1)); - } I915_WRITE(PIPEBSTAT, pipeb_stats); } - /* Clear the generated interrupt */ - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(IIR, iir); - (void) I915_READ(IIR); - } else { - I915_WRITE16(IIR, iir); - (void) I915_READ16(IIR); + I915_WRITE(IIR, iir); + if (dev->pdev->msi_enabled) + I915_WRITE(IMR, dev_priv->irq_mask_reg); + (void) I915_READ(IIR); /* Flush posted writes */ + + /* This is a global event, and not a pipe A event */ + if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS) + hotplug = 1; + + if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS) { + hotplug = 1; + /* Toggle hotplug detection to clear hotplug status */ + tvdac = I915_READ(TV_DAC); + I915_WRITE(TV_DAC, tvdac & ~TVDAC_STATE_CHG_EN); + I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN); } if (dev->primary->master) { @@ -576,22 +589,25 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (iir & I915_USER_INTERRUPT) { + dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); DRM_WAKEUP(&dev_priv->irq_queue); #ifdef I915_HAVE_FENCE i915_fence_handler(dev); #endif } - if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) { - vblank = 1; + if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { + vblank++; drm_handle_vblank(dev, i915_get_plane(dev, 0)); } - if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) { - vblank = 1; + + if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { + vblank++; drm_handle_vblank(dev, i915_get_plane(dev, 1)); } + if (vblank) { if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); @@ -616,9 +632,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) i915_run_hotplug_tasklet(dev, temp2); } - if (dev->pdev->msi_enabled) - I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); - return IRQ_HANDLED; } @@ -646,16 +659,9 @@ void i915_user_irq_on(struct drm_device *dev) struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; DRM_SPINLOCK(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ - dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT; - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(IMR, dev_priv->irq_mask_reg); - else - I915_WRITE16(IMR, dev_priv->irq_mask_reg); - I915_READ16(IMR); - } + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)) + i915_enable_irq(dev_priv, I915_USER_INTERRUPT); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); - } void i915_user_irq_off(struct drm_device *dev) @@ -664,14 +670,8 @@ void i915_user_irq_off(struct drm_device *dev) DRM_SPINLOCK(&dev_priv->user_irq_lock); BUG_ON(dev_priv->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - dev_priv->irq_mask_reg |= I915_USER_INTERRUPT; - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(IMR, dev_priv->irq_mask_reg); - else - I915_WRITE16(IMR, dev_priv->irq_mask_reg); - I915_READ16(IMR); - } + if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) + i915_disable_irq(dev_priv, I915_USER_INTERRUPT); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } @@ -803,11 +803,7 @@ int i915_enable_vblank(struct drm_device *dev, int plane) } DRM_SPINLOCK(&dev_priv->user_irq_lock); - dev_priv->irq_mask_reg &= ~mask_reg; - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(IMR, dev_priv->irq_mask_reg); - else - I915_WRITE16(IMR, dev_priv->irq_mask_reg); + i915_enable_irq(dev_priv, mask_reg); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); return 0; @@ -837,11 +833,7 @@ void i915_disable_vblank(struct drm_device *dev, int plane) } DRM_SPINLOCK(&dev_priv->user_irq_lock); - dev_priv->irq_mask_reg |= mask_reg; - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(IMR, dev_priv->irq_mask_reg); - else - I915_WRITE16(IMR, dev_priv->irq_mask_reg); + i915_disable_irq(dev_priv, mask_reg); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); if (pipestat_reg) { @@ -862,8 +854,8 @@ void i915_enable_interrupt (struct drm_device *dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; struct drm_connector *o; - - dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT; + + dev_priv->irq_mask_reg &= ~0; if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { if (dev->mode_config.num_connector) @@ -925,14 +917,9 @@ void i915_enable_interrupt (struct drm_device *dev) } } - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(IMR, dev_priv->irq_mask_reg); - I915_WRITE(IER, ~dev_priv->irq_mask_reg); - } else { - I915_WRITE16(IMR, dev_priv->irq_mask_reg); - I915_WRITE16(IER, ~(u16)dev_priv->irq_mask_reg); - } - + I915_WRITE(IMR, dev_priv->irq_mask_reg); + I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); + (void) I915_READ (IER); dev_priv->irq_enabled = 1; } @@ -964,17 +951,15 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_vblank_pipe *pipe = data; - u16 flag; + u32 flag = 0; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - flag = I915_READ(IER); - else - flag = I915_READ16(IER); + if (dev_priv->irq_enabled) + flag = ~dev_priv->irq_mask_reg; pipe->pipe = 0; if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) @@ -1158,19 +1143,12 @@ void i915_driver_irq_preinstall(struct drm_device * dev) tmp = I915_READ(PIPEBSTAT); I915_WRITE(PIPEBSTAT, tmp); - - I915_WRITE16(HWSTAM, 0xeffe); - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(IMR, 0x0); - I915_WRITE(IER, 0x0); - tmp = I915_READ(IIR); - I915_WRITE(IIR, tmp); - } else { - I915_WRITE16(IMR, 0x0); - I915_WRITE16(IER, 0x0); - tmp = I915_READ16(IIR); - I915_WRITE16(IIR, tmp); - } + atomic_set(&dev_priv->irq_received, 0); + I915_WRITE(HWSTAM, 0xffff); + I915_WRITE(IER, 0x0); + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IIR, 0xffffffff); + (void) I915_READ(IIR); } int i915_driver_irq_postinstall(struct drm_device * dev) |