From 2655005762b8915d5f44d1d1ee7e6c2eb34841d7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 11 Jun 2008 14:42:40 -0700 Subject: [gem] Move potentially device-specific ioctls to the intel driver. This is the create (may want location flags), pread/pwrite/mmap (performance tuning hints), and set_domain (will 32 bits be enough for everyone?) ioctls. Left in the generic set are just flink/open/close. The 2D driver must be updated for this change, and API but not ABI is broken for 3D. The driver version is bumped to mark this. --- shared-core/drm.h | 83 ++-------------------------------------- shared-core/i915_dma.c | 5 +++ shared-core/i915_drm.h | 101 ++++++++++++++++++++++++++++++++++++++++++++----- shared-core/i915_drv.h | 20 ++++++---- 4 files changed, 113 insertions(+), 96 deletions(-) (limited to 'shared-core') diff --git a/shared-core/drm.h b/shared-core/drm.h index 2373a22e..6012ef21 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -959,69 +959,12 @@ struct drm_mm_info_arg { uint64_t p_size; }; - -struct drm_gem_create { - /** - * Requested size for the object. - * - * The (page-aligned) allocated size for the object will be returned. - */ - uint64_t size; - /** - * Returned handle for the object. - * - * Object handles are nonzero. - */ - uint32_t handle; - uint32_t pad; -}; - struct drm_gem_close { /** Handle of the object to be closed. */ uint32_t handle; uint32_t pad; }; -struct drm_gem_pread { - /** Handle for the object being read. */ - uint32_t handle; - uint32_t pad; - /** Offset into the object to read from */ - uint64_t offset; - /** Length of data to read */ - uint64_t size; - /** Pointer to write the data into. */ - uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ -}; - -struct drm_gem_pwrite { - /** Handle for the object being written to. */ - uint32_t handle; - uint32_t pad; - /** Offset into the object to write to */ - uint64_t offset; - /** Length of data to write */ - uint64_t size; - /** Pointer to read the data from. */ - uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ -}; - -struct drm_gem_mmap { - /** Handle for the object being mapped. */ - uint32_t handle; - uint32_t pad; - /** Offset in the object to map. */ - uint64_t offset; - /** - * Length of data to map. - * - * The value will be page-aligned. - */ - uint64_t size; - /** Returned pointer the data was mapped at */ - uint64_t addr_ptr; /* void *, but pointers are not 32/64 compatible */ -}; - struct drm_gem_flink { /** Handle for the object being named */ uint32_t handle; @@ -1041,19 +984,6 @@ struct drm_gem_open { uint64_t size; }; -struct drm_gem_set_domain { - /** Handle for the object */ - uint32_t handle; - - /** New read domains */ - uint32_t read_domains; - - /** New write domain */ - uint32_t write_domain; -}; - -#define DRM_GEM_DOMAIN_CPU 0x00000001 - /** * \name Ioctls Definitions */ @@ -1075,6 +1005,10 @@ struct drm_gem_set_domain { #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) #define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) +#define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x09, struct drm_gem_close) +#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) +#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) + #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) #define DRM_IOCTL_BLOCK DRM_IOWR(0x12, struct drm_block) @@ -1122,15 +1056,6 @@ struct drm_gem_set_domain { #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) -#define DRM_IOCTL_GEM_CREATE DRM_IOWR(0x09, struct drm_gem_create) -#define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x0a, struct drm_gem_close) -#define DRM_IOCTL_GEM_PREAD DRM_IOW (0x0b, struct drm_gem_pread) -#define DRM_IOCTL_GEM_PWRITE DRM_IOW (0x0c, struct drm_gem_pwrite) -#define DRM_IOCTL_GEM_MMAP DRM_IOWR(0x0d, struct drm_gem_mmap) -#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0e, struct drm_gem_flink) -#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0f, struct drm_gem_open) -#define DRM_IOCTL_GEM_SET_DOMAIN DRM_IOW (0xb7, struct drm_gem_set_domain) - #define DRM_IOCTL_MM_INIT DRM_IOWR(0xc0, struct drm_mm_init_arg) #define DRM_IOCTL_MM_TAKEDOWN DRM_IOWR(0xc1, struct drm_mm_type_arg) #define DRM_IOCTL_MM_LOCK DRM_IOWR(0xc2, struct drm_mm_type_arg) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 4243b4e9..7e4de18b 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1190,6 +1190,11 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), + 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), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index ce01640a..fe47708d 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -183,7 +183,12 @@ typedef struct drm_i915_sarea { #define DRM_I915_GEM_BUSY 0x17 #define DRM_I915_GEM_THROTTLE 0x18 #define DRM_I915_GEM_ENTERVT 0x19 -#define DRM_I915_GEM_LEAVEVT 0x20 +#define DRM_I915_GEM_LEAVEVT 0x1a +#define DRM_I915_GEM_CREATE 0x1b +#define DRM_I915_GEM_PREAD 0x1c +#define DRM_I915_GEM_PWRITE 0x1d +#define DRM_I915_GEM_MMAP 0x1e +#define DRM_I915_GEM_SET_DOMAIN 0x1f #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) @@ -211,6 +216,11 @@ typedef struct drm_i915_sarea { #define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE) #define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT) #define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT) +#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create) +#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread) +#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) /* Asynchronous page flipping: */ @@ -424,6 +434,73 @@ struct drm_i915_gem_init { uint64_t gtt_end; }; +struct drm_i915_gem_create { + /** + * Requested size for the object. + * + * The (page-aligned) allocated size for the object will be returned. + */ + uint64_t size; + /** + * Returned handle for the object. + * + * Object handles are nonzero. + */ + uint32_t handle; + uint32_t pad; +}; + +struct drm_i915_gem_pread { + /** Handle for the object being read. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to read from */ + uint64_t offset; + /** Length of data to read */ + uint64_t size; + /** Pointer to write the data into. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_i915_gem_pwrite { + /** Handle for the object being written to. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to write to */ + uint64_t offset; + /** Length of data to write */ + uint64_t size; + /** Pointer to read the data from. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_i915_gem_mmap { + /** Handle for the object being mapped. */ + uint32_t handle; + uint32_t pad; + /** Offset in the object to map. */ + uint64_t offset; + /** + * Length of data to map. + * + * The value will be page-aligned. + */ + uint64_t size; + /** Returned pointer the data was mapped at */ + uint64_t addr_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_i915_gem_set_domain { + /** Handle for the object */ + uint32_t handle; + + /** New read domains */ + uint32_t read_domains; + + /** New write domain */ + uint32_t write_domain; +}; + struct drm_i915_gem_relocation_entry { /** * Handle of the buffer being pointed to by this relocation entry. @@ -469,20 +546,26 @@ struct drm_i915_gem_relocation_entry { uint32_t write_domain; }; -/** +/** @{ * Intel memory domains * * Most of these just align with the various caches in * the system and are used to flush and invalidate as * objects end up cached in different domains. */ - -/* 0x00000001 is DRM_GEM_DOMAIN_CPU */ -#define DRM_GEM_DOMAIN_I915_RENDER 0x00000002 /* Render cache, used by 2D and 3D drawing */ -#define DRM_GEM_DOMAIN_I915_SAMPLER 0x00000004 /* Sampler cache, used by texture engine */ -#define DRM_GEM_DOMAIN_I915_COMMAND 0x00000008 /* Command queue, used to load batch buffers */ -#define DRM_GEM_DOMAIN_I915_INSTRUCTION 0x00000010 /* Instruction cache, used by shader programs */ -#define DRM_GEM_DOMAIN_I915_VERTEX 0x00000020 /* Vertex address cache */ +/** CPU cache */ +#define I915_GEM_DOMAIN_CPU 0x00000001 +/** Render cache, used by 2D and 3D drawing */ +#define I915_GEM_DOMAIN_RENDER 0x00000002 +/** Sampler cache, used by texture engine */ +#define I915_GEM_DOMAIN_SAMPLER 0x00000004 +/** Command queue, used to load batch buffers */ +#define I915_GEM_DOMAIN_COMMAND 0x00000008 +/** Instruction cache, used by shader programs */ +#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010 +/** Vertex address cache */ +#define I915_GEM_DOMAIN_VERTEX 0x00000020 +/** @} */ struct drm_i915_gem_exec_object { /** diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 3a22ae3c..9c9925b5 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -37,7 +37,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20080312" +#define DRIVER_DATE "20080611" #if defined(__linux__) #define I915_HAVE_FENCE @@ -61,7 +61,7 @@ */ #define DRIVER_MAJOR 1 #if defined(I915_HAVE_FENCE) && defined(I915_HAVE_BUFFER) -#define DRIVER_MINOR 13 +#define DRIVER_MINOR 14 #else #define DRIVER_MINOR 6 #endif @@ -461,6 +461,16 @@ int i915_execbuffer(struct drm_device *dev, void *data, /* i915_gem.c */ int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int i915_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +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_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_pin_ioctl(struct drm_device *dev, void *data, @@ -479,12 +489,6 @@ 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); -int i915_gem_set_domain(struct drm_gem_object *obj, - struct drm_file *file_priv, - uint32_t read_domains, - uint32_t write_domain); -int i915_gem_flush_pwrite(struct drm_gem_object *obj, - uint64_t offset, uint64_t size); void i915_gem_lastclose(struct drm_device *dev); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_timeout(unsigned long data); -- cgit v1.2.3 From 846d792ac10c4b2738bb5ff59e56df168b9921ff Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 11 Jun 2008 15:51:17 -0700 Subject: [gem] Another round of cleanups from checkpatch.pl --- shared-core/i915_drm.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index fe47708d..f16dc99f 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -573,11 +573,15 @@ struct drm_i915_gem_exec_object { * operation. */ uint32_t handle; - - /** List of relocations to be performed on this buffer */ + + /** Number of relocations to be performed on this buffer */ uint32_t relocation_count; - uint64_t relocs_ptr; /* struct drm_i915_gem_relocation_entry *relocs */ - + /** + * Pointer to array of struct drm_i915_gem_relocation_entry containing + * the relocations to be performed in this buffer. + */ + uint64_t relocs_ptr; + /** Required alignment in graphics aperture */ uint64_t alignment; @@ -593,11 +597,13 @@ struct drm_i915_gem_execbuffer { * List of buffers to be validated with their relocations to be * performend on them. * + * This is a pointer to an array of struct drm_i915_gem_validate_entry. + * * These buffers must be listed in an order such that all relocations * a buffer is performing refer to buffers that have already appeared * in the validate list. */ - uint64_t buffers_ptr; /* struct drm_i915_gem_validate_entry *buffers */ + uint64_t buffers_ptr; uint32_t buffer_count; /** Offset in the batchbuffer to start execution from. */ @@ -614,7 +620,7 @@ struct drm_i915_gem_pin { /** Handle of the buffer to be pinned. */ uint32_t handle; uint32_t pad; - + /** alignment required within the aperture */ uint64_t alignment; @@ -631,7 +637,7 @@ struct drm_i915_gem_unpin { struct drm_i915_gem_busy { /** Handle of the buffer to check for busy */ uint32_t handle; - + /** Return busy status (1 if busy, 0 if idle) */ uint32_t busy; }; -- cgit v1.2.3 From cc74ac359053e95fd79d7011a2e18defcefb5c19 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 12 Jun 2008 10:56:37 -0700 Subject: Don't clear USER_INTERRUPT if we're not handling it. This fixes a regression from commit d434b64f6a760d85295e32298a9a1f3624ee1b69 which could cause us to fail to wake up for user interrupts if we lost a race. --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-core') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 0125f8b3..39da8143 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -507,7 +507,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if (dev_priv->sarea_priv) dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - I915_WRITE(I915REG_INT_IDENTITY_R, iir | I915_USER_INTERRUPT); + I915_WRITE(I915REG_INT_IDENTITY_R, iir); (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ if (iir & I915_USER_INTERRUPT) { -- cgit v1.2.3 From 0558d99c01c38e24e97b57ef55f66bb94a92e157 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 13 Jun 2008 09:53:36 -0700 Subject: [gem] Remove the interrupt handler for retiring requests. This was insufficient once we started masking interrupts to only when someone was waiting for them (and would thus retire requests themselves). It was replaced by the retire_timer. --- shared-core/i915_dma.c | 2 -- shared-core/i915_drv.h | 3 --- shared-core/i915_irq.c | 23 ----------------------- 3 files changed, 28 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 7e4de18b..667a6ac0 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1077,8 +1077,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) init_timer_deferrable (&dev_priv->mm.retire_timer); INIT_WORK(&dev_priv->mm.retire_task, i915_gem_retire_handler); - INIT_WORK(&dev_priv->user_interrupt_task, - i915_user_interrupt_handler); dev_priv->mm.next_gem_seqno = 1; #ifdef __linux__ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 9c9925b5..5af9a964 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -300,8 +300,6 @@ typedef struct drm_i915_private { */ int suspended; } mm; - - struct work_struct user_interrupt_task; } drm_i915_private_t; enum intel_chip_family { @@ -421,7 +419,6 @@ extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void i915_user_irq_on(drm_i915_private_t *dev_priv); extern void i915_user_irq_off(drm_i915_private_t *dev_priv); -extern void i915_user_interrupt_handler(struct work_struct *work); /* i915_mem.c */ extern int i915_mem_alloc(struct drm_device *dev, void *data, diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 39da8143..6daf2918 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -435,28 +435,6 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) return count; } -/** - * Handler for user interrupts in process context (able to sleep, do VFS - * operations, etc. - * - * If another IRQ comes in while we're in this handler, it will still get put - * on the queue again to be rerun when we finish. - */ -void -i915_user_interrupt_handler(struct work_struct *work) -{ - drm_i915_private_t *dev_priv; - struct drm_device *dev; - - dev_priv = container_of(work, drm_i915_private_t, - user_interrupt_task); - dev = dev_priv->dev; - - mutex_lock(&dev->struct_mutex); - i915_gem_retire_requests(dev); - mutex_unlock(&dev->struct_mutex); -} - irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -514,7 +492,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev_priv->irq_queue); #ifdef I915_HAVE_FENCE i915_fence_handler(dev); - schedule_work(&dev_priv->user_interrupt_task); #endif } -- cgit v1.2.3 From df4ef348c8a48cead807a42fcd315f7e422aa156 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 13 Jun 2008 10:47:33 -0700 Subject: Fix i915_wait_irq in the presence of interrupt masking. In the short-circuit code for the breadcrumb already being new enough, we need to update the sarea_priv copy of the breadcrumb just as if we had waited. Otherwise userland error checking will notice that we returned too early based on its wrong information, and call wait_irq again (leading to spinning until someone else comes along and updates the sarea_priv). This bug was hidden when we had interrupt masking disabled, such as in master, since the interrupt handler would update sarea_priv. --- shared-core/i915_irq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'shared-core') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6daf2918..cfa9320e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -560,8 +560,12 @@ int i915_wait_irq(struct drm_device * dev, int irq_nr) DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); - if (READ_BREADCRUMB(dev_priv) >= irq_nr) + if (READ_BREADCRUMB(dev_priv) >= irq_nr) { + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); return 0; + } i915_user_irq_on(dev_priv); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, -- cgit v1.2.3 From 462af73149b9286a74b95b9cda5e4224ebe0dd87 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 13 Jun 2008 09:19:30 -0700 Subject: [intel-gem] Use a delayed_work instead of a timer + work_struct We want request retirement to occur about once a second when the request queue is non-empty. This was done with a timer that queued a work_struct, using a delayed_work instead makes a lot more sense. --- shared-core/i915_dma.c | 7 ++----- shared-core/i915_drv.h | 9 +++++---- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 667a6ac0..669f1e4e 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1072,11 +1072,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.request_list); - dev_priv->mm.retire_timer.function = i915_gem_retire_timeout; - dev_priv->mm.retire_timer.data = (unsigned long) dev; - init_timer_deferrable (&dev_priv->mm.retire_timer); - INIT_WORK(&dev_priv->mm.retire_task, - i915_gem_retire_handler); + INIT_DELAYED_WORK(&dev_priv->mm.retire_work, + i915_gem_retire_work_handler); dev_priv->mm.next_gem_seqno = 1; #ifdef __linux__ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 5af9a964..5cc6e680 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -285,8 +285,7 @@ typedef struct drm_i915_private { * fire periodically while the ring is running. When it * fires, go retire requests. */ - struct timer_list retire_timer; - struct work_struct retire_task; + struct delayed_work retire_work; uint32_t next_gem_seqno; @@ -488,8 +487,7 @@ 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); void i915_gem_retire_requests(struct drm_device *dev); -void i915_gem_retire_timeout(unsigned long data); -void i915_gem_retire_handler(struct work_struct *work); +void i915_gem_retire_work_handler(struct work_struct *work); #endif #ifdef __linux__ @@ -915,6 +913,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define XY_SRC_COPY_BLT_SRC_TILED (1<<15) #define XY_SRC_COPY_BLT_DST_TILED (1<<11) +#define MI_NOOP (0) +#define MI_NOOP_ENABLE_NOPID (1 << 22) +#define MI_NOOP_ID_MASK ((1 << 22) - 1) #define MI_BATCH_BUFFER ((0x30<<23)|1) #define MI_BATCH_BUFFER_START (0x31<<23) -- cgit v1.2.3 From 5957470ca3be6c0225985f74b1511401e02c014b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jun 2008 18:19:19 -0700 Subject: [intel] Restructure irq to pend all work until after iir write. The interrupt identity register must be writen before any work occurs lest we drop an interrupt on the floor. This patch just shuffles code around to make sure that IIR is written as early as possible. --- shared-core/i915_irq.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index cfa9320e..58781a4a 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -440,7 +440,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 iir; - u32 pipea_stats, pipeb_stats; + u32 pipea_stats = 0, pipeb_stats = 0; int vblank = 0; iir = I915_READ(I915REG_INT_IDENTITY_R); @@ -463,31 +463,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) */ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { pipea_stats = I915_READ(I915REG_PIPEASTAT); - if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 0)); - } I915_WRITE(I915REG_PIPEASTAT, pipea_stats); } if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 1)); - } I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); } + I915_WRITE(I915REG_INT_IDENTITY_R, iir); + (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted writes */ + if (dev_priv->sarea_priv) dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - I915_WRITE(I915REG_INT_IDENTITY_R, iir); - (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ - if (iir & I915_USER_INTERRUPT) { DRM_WAKEUP(&dev_priv->irq_queue); #ifdef I915_HAVE_FENCE @@ -495,6 +483,16 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) #endif } + if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| + I915_VBLANK_INTERRUPT_STATUS)) { + vblank = 1; + drm_handle_vblank(dev, i915_get_plane(dev, 0)); + } + if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| + I915_VBLANK_INTERRUPT_STATUS)) { + vblank = 1; + drm_handle_vblank(dev, i915_get_plane(dev, 1)); + } if (vblank) { if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); @@ -526,9 +524,11 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) { 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; - I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - (void) I915_READ (I915REG_INT_ENABLE_R); + if ((dev_priv->irq_mask_reg & I915_USER_INTERRUPT) != 0) { + dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT; + I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); + (void) I915_READ (I915REG_INT_MASK_R); + } } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); @@ -539,9 +539,11 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv) 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; - I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - (void) I915_READ(I915REG_INT_MASK_R); + if ((dev_priv->irq_mask_reg & I915_USER_INTERRUPT) == 0) { + dev_priv->irq_mask_reg |= I915_USER_INTERRUPT; + I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); + (void) I915_READ(I915REG_INT_MASK_R); + } } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } -- cgit v1.2.3 From 3762c9ea6754763694b1de4df3acd9dc37247f87 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 13 Jun 2008 10:27:39 -0700 Subject: [intel] Enable MSI for i915 IRQ --- shared-core/i915_irq.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 58781a4a..9ba5b00a 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -33,6 +33,13 @@ #define MAX_NOPID ((u32)~0) +/* + * These are the interrupts used by the driver + */ +#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \ + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) + /** * i915_get_pipe - return the the pipe associated with a given plane * @dev: DRM device @@ -443,6 +450,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) u32 pipea_stats = 0, pipeb_stats = 0; int vblank = 0; + if (dev->pdev->msi_enabled) + I915_WRITE(I915REG_INT_ENABLE_R, 0); iir = I915_READ(I915REG_INT_IDENTITY_R); #if 0 DRM_DEBUG("flag=%08x\n", iir); @@ -454,6 +463,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_READ(I915REG_INT_ENABLE_R), I915_READ(I915REG_PIPEASTAT), I915_READ(I915REG_PIPEBSTAT)); + if (dev->pdev->msi_enabled) + I915_WRITE(I915REG_INT_ENABLE_R, + I915_INTERRUPT_ENABLE_MASK); return IRQ_NONE; } @@ -498,6 +510,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) drm_locked_tasklet(dev, i915_vblank_tasklet); } + if (dev->pdev->msi_enabled) + I915_WRITE(I915REG_INT_ENABLE_R, I915_INTERRUPT_ENABLE_MASK); return IRQ_HANDLED; } @@ -724,11 +738,9 @@ static void i915_enable_interrupt (struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->irq_mask_reg = (I915_USER_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); + dev_priv->irq_mask_reg = I915_INTERRUPT_ENABLE_MASK; I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_mask_reg); + I915_WRITE(I915REG_INT_ENABLE_R, I915_INTERRUPT_ENABLE_MASK); (void) I915_READ (I915REG_INT_ENABLE_R); dev_priv->irq_enabled = 1; } -- cgit v1.2.3 From ced9ebf64543b4d64a38feee3293040af953acc0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 13 Jun 2008 12:06:13 -0700 Subject: [intel-gem] throttle based on frames rather than time. Reduces jitter. Record the last execbuffer sequence for each client. Record that sequence in the throttle ioctl as the 'throttle sequence'. Wait for the last throttle sequence in the throttle ioctl. --- shared-core/i915_dma.c | 26 ++++++++++++++++++++++++++ shared-core/i915_drv.h | 10 ++++++++++ 2 files changed, 36 insertions(+) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 669f1e4e..2157c594 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1149,12 +1149,38 @@ void i915_driver_lastclose(struct drm_device * dev) i915_dma_cleanup(dev); } +int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) +{ + struct drm_i915_file_private *i915_file_priv; + + DRM_DEBUG("\n"); + i915_file_priv = (struct drm_i915_file_private *) + drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES); + + if (!i915_file_priv) + return -ENOMEM; + + file_priv->driver_priv = i915_file_priv; + + i915_file_priv->mm.last_gem_seqno = 0; + i915_file_priv->mm.last_gem_throttle_seqno = 0; + + return 0; +} + void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; i915_mem_release(dev, file_priv, dev_priv->agp_heap); } +void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) +{ + struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; + + drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); +} + struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 5cc6e680..334bc43f 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -301,6 +301,13 @@ typedef struct drm_i915_private { } mm; } drm_i915_private_t; +struct drm_i915_file_private { + struct { + uint32_t last_gem_seqno; + uint32_t last_gem_throttle_seqno; + } mm; +}; + enum intel_chip_family { CHIP_I8XX = 0x01, CHIP_I9XX = 0x02, @@ -378,8 +385,11 @@ extern void i915_kernel_lost_context(struct drm_device * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); extern int i915_driver_unload(struct drm_device *); extern void i915_driver_lastclose(struct drm_device * dev); +extern int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv); extern void i915_driver_preclose(struct drm_device *dev, struct drm_file *file_priv); +extern void i915_driver_postclose(struct drm_device *dev, + struct drm_file *file_priv); extern int i915_driver_device_is_agp(struct drm_device * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -- cgit v1.2.3 From c847271179da382af52a6874e2edec586b88af75 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 16 Jun 2008 13:09:31 -0700 Subject: [linux] Use the device's irq for handler setup instead of stale dev->irq. This fixes registration when MSI is set up after the stub function fills in dev->irq. Otherwise /proc/interrupts would report attachment to the fasteoi interrupt. dev->irq is still exposed (and updated at IRQ setup) for the drivers that use it for whatever reason. --- shared-core/i915_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 2157c594..2db6be07 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -150,7 +150,7 @@ static int i915_dma_cleanup(struct drm_device * dev) * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if (dev->irq) + if (dev->irq_enabled) drm_irq_uninstall(dev); if (dev_priv->ring.virtual_start) { @@ -889,7 +889,7 @@ static int i915_getparam(struct drm_device *dev, void *data, switch (param->param) { case I915_PARAM_IRQ_ACTIVE: - value = dev->irq ? 1 : 0; + value = dev->irq_enabled ? 1 : 0; break; case I915_PARAM_ALLOW_BATCHBUFFER: value = dev_priv->allow_batchbuffer ? 1 : 0; -- cgit v1.2.3