From db689c7b95613237cec904c3f6ee27e8c2bf7ce0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Jun 2007 10:44:21 -0700 Subject: Initial checkin of vblank rework. Code attempts to reduce the number of vblank interrupt in order to save power. --- linux-core/drmP.h | 12 +++++---- linux-core/drm_irq.c | 69 +++++++++++++++++++++++++++++++++++++++------------ linux-core/i915_drv.c | 5 ++-- 3 files changed, 63 insertions(+), 23 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index dd3a69df..c3f20311 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -627,8 +627,9 @@ struct drm_driver { int (*kernel_context_switch) (struct drm_device * dev, int old, int new); void (*kernel_context_switch_unlock) (struct drm_device * dev); - int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); - int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence); + u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); + void (*enable_vblank) (struct drm_device *dev, int crtc); + void (*disable_vblank) (struct drm_device *dev, int crtc); int (*dri_library_name) (struct drm_device * dev, char * buf); /** @@ -783,12 +784,13 @@ typedef struct drm_device { /*@{ */ wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ - atomic_t vbl_received; - atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ + atomic_t *vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ spinlock_t vbl_lock; struct list_head vbl_sigs; /**< signal list to send on VBLANK */ struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ - unsigned int vbl_pending; + atomic_t *vbl_pending; + u32 *last_vblank; /* protected by dev->vbl_lock */ + unsigned long max_vblank_count; /**< size of vblank counter register */ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ void (*locked_tasklet_func)(struct drm_device *dev); diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 88716712..f229f778 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -221,6 +221,44 @@ int drm_control(struct inode *inode, struct file *filp, } } +static void drm_vblank_get(drm_device_t *dev, int crtc) +{ + unsigned long irqflags; + u32 cur_vblank, diff; + + if (atomic_add_return(1, &dev->vbl_pending[crtc]) != 1) + return; + + /* + * Interrupts were disabled prior to this call, so deal with counter + * wrap if needed. + * NOTE! It's possible we lost a full dev->max_vblank_count events + * here if the register is small or we had vblank interrupts off for + * a long time. + */ + cur_vblank = dev->driver->get_vblank_counter(dev, crtc); + spin_lock_irqsave(&dev->vbl_lock, irqflags); + if (cur_vblank < dev->last_vblank[crtc]) { + diff = dev->max_vblank_count - + dev->last_vblank[crtc]; + diff += cur_vblank; + } else { + diff = cur_vblank - last_vblank; + } + dev->last_vblank[crtc] = cur_vblank; + spin_lock_irqrestore(&dev->vbl_lock, irqflags); + + atomic_add(diff, &dev->vblank_count[crtc]); + dev->driver->enable_vblank(dev, crtc); +} + +static void drm_vblank_put(drm_device_t *dev, int crtc) +{ + if (atomic_dec_and_test(&dev->vbl_pending[crtc])) + dev->driver->disable_vblank(dev, crtc); +} + + /** * Wait for VBLANK. * @@ -248,7 +286,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) drm_wait_vblank_t vblwait; struct timeval now; int ret = 0; - unsigned int flags, seq; + unsigned int flags, seq, crtc; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -265,13 +303,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) } flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; + crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 - : &dev->vbl_received); + drm_vblank_get(dev, crtc); + seq = atomic_read(&dev->vblank_count[crtc]); switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: @@ -307,22 +346,23 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->vbl_lock, irqflags); vblwait.reply.sequence = seq; + drm_vblank_put(dev, crtc); goto done; } } - if (dev->vbl_pending >= 100) { + if (atomic_read(&dev->vbl_pending[crtc]) >= 100) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + drm_vblank_put(dev, crtc); return -EBUSY; } - dev->vbl_pending++; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); if (! (vbl_sig = drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) { + drm_vblank_put(dev, crtc); return -ENOMEM; } @@ -340,14 +380,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) vblwait.reply.sequence = seq; } else { - if (flags & _DRM_VBLANK_SECONDARY) { - if (dev->driver->vblank_wait2) - ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence); - } else if (dev->driver->vblank_wait) - ret = - dev->driver->vblank_wait(dev, - &vblwait.request.sequence); + unsigned long cur_vblank; + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(&dev->vblank_count[crtc])) + - seq) <= (1 << 23))); + drm_vblank_put(dev, crtc); do_gettimeofday(&now); vblwait.reply.tval_sec = now.tv_sec; vblwait.reply.tval_usec = now.tv_usec; @@ -379,8 +417,7 @@ void drm_vbl_send_signals(drm_device_t * dev) for (i = 0; i < 2; i++) { drm_vbl_sig_t *vbl_sig, *tmp; struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; - unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : - &dev->vbl_received); + unsigned int vbl_seq = atomic_read(&dev->vblank_count[i]); list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { @@ -393,7 +430,7 @@ void drm_vbl_send_signals(drm_device_t * dev) drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER); - dev->vbl_pending--; + drm_vblank_put(dev, i); } } } diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 7fdb0839..e7a9bfdc 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -83,8 +83,9 @@ static struct drm_driver driver = { .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, - .vblank_wait = i915_driver_vblank_wait, - .vblank_wait2 = i915_driver_vblank_wait2, + .get_vblank_counter = i915_get_vblank_counter, + .enable_vblank = i915_enable_vblank, + .disable_vblank = i915_disable_vblank, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, .irq_uninstall = i915_driver_irq_uninstall, -- cgit v1.2.3 From ca47fa90b73d0eac73fb7d1ba712d81e180eae7d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Jun 2007 13:35:41 -0700 Subject: Update vblank code: - move pre/post modeset ioctl to core - fixup i915 buffer swap - fix outstanding signal count code - create new core vblank init routine - test (works with glxgears) - simplify i915 interrupt handler --- linux-core/drmP.h | 22 ++++++-- linux-core/drm_drv.c | 1 + linux-core/drm_irq.c | 145 ++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 137 insertions(+), 31 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index c3f20311..c8b72257 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -648,7 +648,7 @@ struct drm_driver { /* these have to be filled in */ irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); void (*irq_preinstall) (struct drm_device * dev); - void (*irq_postinstall) (struct drm_device * dev); + int (*irq_postinstall) (struct drm_device * dev); void (*irq_uninstall) (struct drm_device * dev); void (*reclaim_buffers) (struct drm_device *dev, struct file * filp); void (*reclaim_buffers_locked) (struct drm_device *dev, @@ -786,10 +786,14 @@ typedef struct drm_device { wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ atomic_t *vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ spinlock_t vbl_lock; - struct list_head vbl_sigs; /**< signal list to send on VBLANK */ - struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ - atomic_t *vbl_pending; - u32 *last_vblank; /* protected by dev->vbl_lock */ + struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ + atomic_t vbl_pending; /* number of signals pending on all crtcs*/ + atomic_t *vblank_usage; /* number of users of vblank interrupts per crtc */ + u32 *last_vblank; /* protected by dev->vbl_lock, used */ + /* for wraparound handling */ + u32 *vblank_offset; /* used to track how many vblanks */ + u32 *vblank_premodeset; /* were lost during modeset */ + unsigned long max_vblank_count; /**< size of vblank counter register */ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ void (*locked_tasklet_func)(struct drm_device *dev); @@ -810,6 +814,7 @@ typedef struct drm_device { #ifdef __alpha__ struct pci_controller *hose; #endif + int num_crtcs; /**< Number of CRTCs on this device */ drm_sg_mem_t *sg; /**< Scatter gather memory */ void *dev_private; /**< device private data */ drm_sigdata_t sigdata; /**< For block_all_signals */ @@ -1074,11 +1079,18 @@ extern void drm_driver_irq_preinstall(drm_device_t * dev); extern void drm_driver_irq_postinstall(drm_device_t * dev); extern void drm_driver_irq_uninstall(drm_device_t * dev); +extern int drm_vblank_init(drm_device_t *dev, int num_crtcs); extern int drm_wait_vblank(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq); extern void drm_vbl_send_signals(drm_device_t * dev); extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*)); +extern void drm_vblank_get(drm_device_t *dev, int crtc); +extern void drm_vblank_put(drm_device_t *dev, int crtc); + + /* Modesetting support */ +extern int drm_modeset_ctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); /* AGP/GART support (drm_agpsupport.h) */ extern drm_agp_head_t *drm_agp_init(drm_device_t *dev); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index d5eb9713..1b37ee4a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -123,6 +123,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { DRM_AUTH }, [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODESET_CTL)] = {drm_modeset_ctl, 0}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index f229f778..8125b75c 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -77,6 +77,70 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, return 0; } +int drm_vblank_init(drm_device_t *dev, int num_crtcs) +{ + int i, ret = -ENOMEM; + + init_waitqueue_head(&dev->vbl_queue); + spin_lock_init(&dev->vbl_lock); + atomic_set(&dev->vbl_pending, 0); + dev->num_crtcs = num_crtcs; + + dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vbl_sigs) + goto err; + + dev->vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vblank_count) + goto err; + + dev->vblank_usage = drm_alloc(sizeof(atomic_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vblank_count) + goto err; + + dev->last_vblank = drm_alloc(sizeof(u32) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->last_vblank) + goto err; + + dev->vblank_premodeset = drm_alloc(sizeof(u32) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vblank_premodeset) + goto err; + + dev->vblank_offset = drm_alloc(sizeof(u32) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vblank_offset) + goto err; + + /* Zero per-crtc vblank stuff */ + for (i = 0; i < num_crtcs; i++) { + INIT_LIST_HEAD(&dev->vbl_sigs[i]); + atomic_set(&dev->vblank_count[i], 0); + atomic_set(&dev->vblank_usage[i], 0); + dev->last_vblank[i] = 0; + dev->vblank_premodeset[i] = 0; + dev->vblank_offset[i] = 0; + } + + ret = 0; + goto out; + +err: + kfree(dev->vbl_sigs); + kfree(dev->vblank_count); + kfree(dev->vblank_usage); + kfree(dev->last_vblank); + kfree(dev->vblank_premodeset); + kfree(dev->vblank_offset); +out: + return ret; +} +EXPORT_SYMBOL(drm_vblank_init); + /** * Install IRQ handler. * @@ -88,7 +152,7 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, */ static int drm_irq_install(drm_device_t * dev) { - int ret; + int ret = 0; unsigned long sh_flags = 0; if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) @@ -114,17 +178,6 @@ static int drm_irq_install(drm_device_t * dev) DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq); - if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { - init_waitqueue_head(&dev->vbl_queue); - - spin_lock_init(&dev->vbl_lock); - - INIT_LIST_HEAD(&dev->vbl_sigs); - INIT_LIST_HEAD(&dev->vbl_sigs2); - - dev->vbl_pending = 0; - } - /* Before installing handler */ dev->driver->irq_preinstall(dev); @@ -142,9 +195,9 @@ static int drm_irq_install(drm_device_t * dev) } /* After installing handler */ - dev->driver->irq_postinstall(dev); + ret = dev->driver->irq_postinstall(dev); - return 0; + return ret; } /** @@ -221,12 +274,12 @@ int drm_control(struct inode *inode, struct file *filp, } } -static void drm_vblank_get(drm_device_t *dev, int crtc) +void drm_vblank_get(drm_device_t *dev, int crtc) { unsigned long irqflags; u32 cur_vblank, diff; - if (atomic_add_return(1, &dev->vbl_pending[crtc]) != 1) + if (atomic_add_return(1, &dev->vblank_count[crtc]) != 1) return; /* @@ -243,21 +296,60 @@ static void drm_vblank_get(drm_device_t *dev, int crtc) dev->last_vblank[crtc]; diff += cur_vblank; } else { - diff = cur_vblank - last_vblank; + diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - spin_lock_irqrestore(&dev->vbl_lock, irqflags); + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); atomic_add(diff, &dev->vblank_count[crtc]); dev->driver->enable_vblank(dev, crtc); } +EXPORT_SYMBOL(drm_vblank_get); -static void drm_vblank_put(drm_device_t *dev, int crtc) +void drm_vblank_put(drm_device_t *dev, int crtc) { - if (atomic_dec_and_test(&dev->vbl_pending[crtc])) + if (atomic_dec_and_test(&dev->vblank_count[crtc])) dev->driver->disable_vblank(dev, crtc); } +EXPORT_SYMBOL(drm_vblank_put); +int drm_modeset_ctl(DRM_IOCTL_ARGS) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_modeset_ctl_t __user *argp = (void __user *)data; + drm_modeset_ctl_t modeset; + int crtc, ret = 0; + u32 new; + + if (copy_from_user(&modeset, argp, sizeof(modeset))) { + ret = -EFAULT; + goto out; + } + + crtc = modeset.arg; + if (crtc > dev->num_crtcs) { + ret = -EINVAL; + goto out; + } + + switch (modeset.cmd) { + case _DRM_PRE_MODESET: + dev->vblank_premodeset[crtc] = + dev->driver->get_vblank_counter(dev, crtc); + break; + case _DRM_POST_MODESET: + new = dev->driver->get_vblank_counter(dev, crtc); + dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; + break; + default: + ret = -EINVAL; + break; + } + +out: + return ret; +} /** * Wait for VBLANK. @@ -329,8 +421,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; - struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) - ? &dev->vbl_sigs2 : &dev->vbl_sigs; + struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; drm_vbl_sig_t *vbl_sig; spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -351,7 +442,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) } } - if (atomic_read(&dev->vbl_pending[crtc]) >= 100) { + if (atomic_read(&dev->vbl_pending) >= 100) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); drm_vblank_put(dev, crtc); return -EBUSY; @@ -359,6 +450,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + atomic_inc(&dev->vbl_pending); + if (! (vbl_sig = drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) { @@ -414,9 +507,9 @@ void drm_vbl_send_signals(drm_device_t * dev) spin_lock_irqsave(&dev->vbl_lock, flags); - for (i = 0; i < 2; i++) { + for (i = 0; i < dev->num_crtcs; i++) { drm_vbl_sig_t *vbl_sig, *tmp; - struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; + struct list_head *vbl_sigs = &dev->vbl_sigs[i]; unsigned int vbl_seq = atomic_read(&dev->vblank_count[i]); list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { @@ -429,7 +522,7 @@ void drm_vbl_send_signals(drm_device_t * dev) drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER); - + atomic_dec(&dev->vbl_pending); drm_vblank_put(dev, i); } } -- cgit v1.2.3 From b06268294afb47e62949984d73905344dd160262 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 14 Jun 2007 11:32:31 -0700 Subject: Comment new vblank routines and fixup several issues: - use correct refcount variable in get/put routines - extract counter update from drm_vblank_get - make signal handling callback per-crtc - update interrupt handling logic, drivers should use drm_handle_vblank - move wakeup and counter update logic to new drm_handle_vblank routine - fixup usage of get/put in light of counter update extraction - fix longstanding bug in signal code, update pending counter only *after* we're sure we'll setup signal handling --- linux-core/drmP.h | 55 +++++++++++++-- linux-core/drm_irq.c | 191 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 188 insertions(+), 58 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index c8b72257..b6cc7cb1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -627,8 +627,49 @@ struct drm_driver { int (*kernel_context_switch) (struct drm_device * dev, int old, int new); void (*kernel_context_switch_unlock) (struct drm_device * dev); + /** + * get_vblank_counter - get raw hardware vblank counter + * @dev: DRM device + * @crtc: counter to fetch + * + * Driver callback for fetching a raw hardware vblank counter + * for @crtc. If a device doesn't have a hardware counter, the + * driver can simply return the value of drm_vblank_count and + * make the enable_vblank() and disable_vblank() hooks into no-ops, + * leaving interrupts enabled at all times. + * + * Wraparound handling and loss of events due to modesetting is dealt + * with in the DRM core code. + * + * RETURNS + * Raw vblank counter value. + */ u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); - void (*enable_vblank) (struct drm_device *dev, int crtc); + + /** + * enable_vblank - enable vblank interrupt events + * @dev: DRM device + * @crtc: which irq to enable + * + * Enable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, this routine should be a no-op, since + * interrupts will have to stay on to keep the count accurate. + * + * RETURNS + * Zero on success, appropriate errno if the given @crtc's vblank + * interrupt cannot be enabled. + */ + int (*enable_vblank) (struct drm_device *dev, int crtc); + + /** + * disable_vblank - disable vblank interrupt events + * @dev: DRM device + * @crtc: which irq to enable + * + * Disable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, this routine should be a no-op, since + * interrupts will have to stay on to keep the count accurate. + */ void (*disable_vblank) (struct drm_device *dev, int crtc); int (*dri_library_name) (struct drm_device * dev, char * buf); @@ -784,11 +825,11 @@ typedef struct drm_device { /*@{ */ wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ - atomic_t *vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ + atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ spinlock_t vbl_lock; struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ - atomic_t vbl_pending; /* number of signals pending on all crtcs*/ - atomic_t *vblank_usage; /* number of users of vblank interrupts per crtc */ + atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ + atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ @@ -1083,9 +1124,11 @@ extern int drm_vblank_init(drm_device_t *dev, int num_crtcs); extern int drm_wait_vblank(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq); -extern void drm_vbl_send_signals(drm_device_t * dev); extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*)); -extern void drm_vblank_get(drm_device_t *dev, int crtc); +extern u32 drm_vblank_count(drm_device_t *dev, int crtc); +extern void drm_update_vblank_count(drm_device_t *dev, int crtc); +extern void drm_handle_vblank(drm_device_t *dev, int crtc); +extern int drm_vblank_get(drm_device_t *dev, int crtc); extern void drm_vblank_put(drm_device_t *dev, int crtc); /* Modesetting support */ diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 8125b75c..7bdb01b2 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -83,7 +83,7 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) init_waitqueue_head(&dev->vbl_queue); spin_lock_init(&dev->vbl_lock); - atomic_set(&dev->vbl_pending, 0); + atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, @@ -91,14 +91,14 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) if (!dev->vbl_sigs) goto err; - dev->vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, + dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, DRM_MEM_DRIVER); - if (!dev->vblank_count) + if (!dev->_vblank_count) goto err; - dev->vblank_usage = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vblank_count) + dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vblank_refcount) goto err; dev->last_vblank = drm_alloc(sizeof(u32) * num_crtcs, @@ -119,24 +119,28 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) /* Zero per-crtc vblank stuff */ for (i = 0; i < num_crtcs; i++) { INIT_LIST_HEAD(&dev->vbl_sigs[i]); - atomic_set(&dev->vblank_count[i], 0); - atomic_set(&dev->vblank_usage[i], 0); + atomic_set(&dev->_vblank_count[i], 0); + atomic_set(&dev->vblank_refcount[i], 0); dev->last_vblank[i] = 0; dev->vblank_premodeset[i] = 0; dev->vblank_offset[i] = 0; } - ret = 0; - goto out; + return 0; err: - kfree(dev->vbl_sigs); - kfree(dev->vblank_count); - kfree(dev->vblank_usage); - kfree(dev->last_vblank); - kfree(dev->vblank_premodeset); - kfree(dev->vblank_offset); -out: + drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * + num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * + num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * num_crtcs, + DRM_MEM_DRIVER); return ret; } EXPORT_SYMBOL(drm_vblank_init); @@ -274,14 +278,37 @@ int drm_control(struct inode *inode, struct file *filp, } } -void drm_vblank_get(drm_device_t *dev, int crtc) +/** + * drm_vblank_count - retrieve "cooked" vblank counter value + * @dev: DRM device + * @crtc: which counter to retrieve + * + * Fetches the "cooked" vblank count value that represents the number of + * vblank events since the system was booted, including lost events due to + * modesetting activity. + */ +u32 drm_vblank_count(drm_device_t *dev, int crtc) +{ + return atomic_read(&dev->_vblank_count[crtc]) + + dev->vblank_offset[crtc]; +} +EXPORT_SYMBOL(drm_vblank_count); + +/** + * drm_update_vblank_count - update the master vblank counter + * @dev: DRM device + * @crtc: counter to update + * + * Call back into the driver to update the appropriate vblank counter + * (specified by @crtc). Deal with wraparound, if it occurred, and + * update the last read value so we can deal with wraparound on the next + * call if necessary. + */ +void drm_update_vblank_count(drm_device_t *dev, int crtc) { unsigned long irqflags; u32 cur_vblank, diff; - if (atomic_add_return(1, &dev->vblank_count[crtc]) != 1) - return; - /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -301,18 +328,61 @@ void drm_vblank_get(drm_device_t *dev, int crtc) dev->last_vblank[crtc] = cur_vblank; spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - atomic_add(diff, &dev->vblank_count[crtc]); - dev->driver->enable_vblank(dev, crtc); + atomic_add(diff, &dev->_vblank_count[crtc]); +} +EXPORT_SYMBOL(drm_update_vblank_count); + +/** + * drm_vblank_get - get a reference count on vblank events + * @dev: DRM device + * @crtc: which CRTC to own + * + * Acquire a reference count on vblank events to avoid having them disabled + * while in use. Note callers will probably want to update the master counter + * using drm_update_vblank_count() above before calling this routine so that + * wakeups occur on the right vblank event. + * + * RETURNS + * Zero on success, nonzero on failure. + */ +int drm_vblank_get(drm_device_t *dev, int crtc) +{ + int ret = 0; + + /* Going from 0->1 means we have to enable interrupts again */ + if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { + ret = dev->driver->enable_vblank(dev, crtc); + if (ret) + atomic_dec(&dev->vblank_refcount[crtc]); + } + + return ret; } EXPORT_SYMBOL(drm_vblank_get); +/** + * drm_vblank_put - give up ownership of vblank events + * @dev: DRM device + * @crtc: which counter to give up + * + * Release ownership of a given vblank counter, turning off interrupts + * if possible. + */ void drm_vblank_put(drm_device_t *dev, int crtc) { - if (atomic_dec_and_test(&dev->vblank_count[crtc])) + /* Last user can disable interrupts */ + if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) dev->driver->disable_vblank(dev, crtc); } EXPORT_SYMBOL(drm_vblank_put); +/** + * drm_modeset_ctl - handle vblank event counter changes across mode switch + * @DRM_IOCTL_ARGS: standard ioctl arguments + * + * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET + * ioctls around modesetting so that any lost vblank events are accounted for. + */ int drm_modeset_ctl(DRM_IOCTL_ARGS) { drm_file_t *priv = filp->private_data; @@ -401,8 +471,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - drm_vblank_get(dev, crtc); - seq = atomic_read(&dev->vblank_count[crtc]); + drm_update_vblank_count(dev, crtc); + seq = drm_vblank_count(dev, crtc); switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: @@ -437,28 +507,28 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->vbl_lock, irqflags); vblwait.reply.sequence = seq; - drm_vblank_put(dev, crtc); goto done; } } - if (atomic_read(&dev->vbl_pending) >= 100) { + if (atomic_read(&dev->vbl_signal_pending) >= 100) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - drm_vblank_put(dev, crtc); return -EBUSY; } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - atomic_inc(&dev->vbl_pending); - if (! (vbl_sig = drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) { - drm_vblank_put(dev, crtc); return -ENOMEM; } + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; + atomic_inc(&dev->vbl_signal_pending); + memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); vbl_sig->sequence = vblwait.request.sequence; @@ -475,8 +545,11 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) } else { unsigned long cur_vblank; + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, - (((cur_vblank = atomic_read(&dev->vblank_count[crtc])) + (((cur_vblank = drm_vblank_count(dev, crtc)) - seq) <= (1 << 23))); drm_vblank_put(dev, crtc); do_gettimeofday(&now); @@ -495,42 +568,56 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) * Send the VBLANK signals. * * \param dev DRM device. + * \param crtc CRTC where the vblank event occurred * * Sends a signal for each task in drm_device::vbl_sigs and empties the list. * * If a signal is not requested, then calls vblank_wait(). */ -void drm_vbl_send_signals(drm_device_t * dev) +static void drm_vbl_send_signals(drm_device_t * dev, int crtc) { + drm_vbl_sig_t *vbl_sig, *tmp; + struct list_head *vbl_sigs; + unsigned int vbl_seq; unsigned long flags; - int i; spin_lock_irqsave(&dev->vbl_lock, flags); - for (i = 0; i < dev->num_crtcs; i++) { - drm_vbl_sig_t *vbl_sig, *tmp; - struct list_head *vbl_sigs = &dev->vbl_sigs[i]; - unsigned int vbl_seq = atomic_read(&dev->vblank_count[i]); + vbl_sigs = &dev->vbl_sigs[crtc]; + vbl_seq = drm_vblank_count(dev, crtc); - list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info(vbl_sig->info.si_signo, - &vbl_sig->info, vbl_sig->task); + list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { + if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { + vbl_sig->info.si_code = vbl_seq; + send_sig_info(vbl_sig->info.si_signo, + &vbl_sig->info, vbl_sig->task); - list_del(&vbl_sig->head); + list_del(&vbl_sig->head); - drm_free(vbl_sig, sizeof(*vbl_sig), - DRM_MEM_DRIVER); - atomic_dec(&dev->vbl_pending); - drm_vblank_put(dev, i); - } - } + drm_free(vbl_sig, sizeof(*vbl_sig), + DRM_MEM_DRIVER); + atomic_dec(&dev->vbl_signal_pending); + drm_vblank_put(dev, crtc); + } } spin_unlock_irqrestore(&dev->vbl_lock, flags); } -EXPORT_SYMBOL(drm_vbl_send_signals); + +/** + * drm_handle_vblank - handle a vblank event + * @dev: DRM device + * @crtc: where this event occurred + * + * Drivers should call this routine in their vblank interrupt handlers to + * update the vblank counter and send any signals that may be pending. + */ +void drm_handle_vblank(drm_device_t *dev, int crtc) +{ + drm_update_vblank_count(dev, crtc); + drm_vbl_send_signals(dev, crtc); +} +EXPORT_SYMBOL(drm_handle_vblank); /** * Tasklet wrapper function. -- cgit v1.2.3 From 1000d88ddfcd0ae769125db37d4e78643a430caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 10:10:33 +0200 Subject: Fix memory leaks in vblank error paths. Also use drm_calloc instead of drm_alloc and memset, and use the size of the struct instead of the size of the pointer for allocation... --- linux-core/drm_irq.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 7bdb01b2..f73d067f 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -518,18 +518,19 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - if (! - (vbl_sig = - drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) { + vbl_sig = drm_calloc(1, sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER); + if (!vbl_sig) { return -ENOMEM; } ret = drm_vblank_get(dev, crtc); - if (ret) + if (ret) { + drm_free(vbl_sig, sizeof(drm_vbl_sig_t), + DRM_MEM_DRIVER); return ret; - atomic_inc(&dev->vbl_signal_pending); + } - memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); + atomic_inc(&dev->vbl_signal_pending); vbl_sig->sequence = vblwait.request.sequence; vbl_sig->info.si_signo = vblwait.request.signal; -- cgit v1.2.3 From 7f95a06c61f585cbc4b5fefc833432178550fe31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 10:12:23 +0200 Subject: Return current sequence number to userspace after blocking wait for vblank. --- linux-core/drm_irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index f73d067f..b4e3c10f 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -556,6 +556,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) do_gettimeofday(&now); vblwait.reply.tval_sec = now.tv_sec; vblwait.reply.tval_usec = now.tv_usec; + vblwait.reply.sequence = cur_vblank; } done: -- cgit v1.2.3 From 82e2c3304d3f1697537b73a2c888c8c6b1b6cdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 10:25:50 +0200 Subject: Wake up vblank waitqueue in drm_handle_vblank(). --- linux-core/drm_irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index b4e3c10f..3dcde9a5 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -617,6 +617,7 @@ static void drm_vbl_send_signals(drm_device_t * dev, int crtc) void drm_handle_vblank(drm_device_t *dev, int crtc) { drm_update_vblank_count(dev, crtc); + DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev, crtc); } EXPORT_SYMBOL(drm_handle_vblank); -- cgit v1.2.3 From fbee089aca727c92e0aa5d7a2ae7a8c5cf9c3076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 10:49:16 +0200 Subject: Make vblank waitqueue per CRTC. --- linux-core/drmP.h | 2 +- linux-core/drm_irq.c | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index b6cc7cb1..5bc8a6c7 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -824,7 +824,7 @@ typedef struct drm_device { /** \name VBLANK IRQ support */ /*@{ */ - wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ + wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ spinlock_t vbl_lock; struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 3dcde9a5..f673a97c 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -81,11 +81,15 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) { int i, ret = -ENOMEM; - init_waitqueue_head(&dev->vbl_queue); spin_lock_init(&dev->vbl_lock); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; + dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vbl_queue) + goto err; + dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, DRM_MEM_DRIVER); if (!dev->vbl_sigs) @@ -118,6 +122,7 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) /* Zero per-crtc vblank stuff */ for (i = 0; i < num_crtcs; i++) { + init_waitqueue_head(&dev->vbl_queue[i]); INIT_LIST_HEAD(&dev->vbl_sigs[i]); atomic_set(&dev->_vblank_count[i], 0); atomic_set(&dev->vblank_refcount[i], 0); @@ -129,6 +134,8 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) return 0; err: + drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * num_crtcs, + DRM_MEM_DRIVER); drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * num_crtcs, DRM_MEM_DRIVER); drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * num_crtcs, @@ -150,7 +157,7 @@ EXPORT_SYMBOL(drm_vblank_init); * * \param dev DRM device. * - * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver + * Initializes the IRQ related data. Installs the handler, calling the driver * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions * before and after the installation. */ @@ -549,7 +556,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) ret = drm_vblank_get(dev, crtc); if (ret) return ret; - DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, (((cur_vblank = drm_vblank_count(dev, crtc)) - seq) <= (1 << 23))); drm_vblank_put(dev, crtc); @@ -617,7 +624,7 @@ static void drm_vbl_send_signals(drm_device_t * dev, int crtc) void drm_handle_vblank(drm_device_t *dev, int crtc) { drm_update_vblank_count(dev, crtc); - DRM_WAKEUP(&dev->vbl_queue); + DRM_WAKEUP(&dev->vbl_queue[crtc]); drm_vbl_send_signals(dev, crtc); } EXPORT_SYMBOL(drm_handle_vblank); -- cgit v1.2.3 From 0f5334be2bc6ceca971a7a6ab3ca1c23a707867c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 11:01:51 +0200 Subject: Remove DRIVER_IRQ_VBL(2). If the driver doesn't support vertical blank interrupts, it won't call drm_vblank_init(), and dev->num_crtcs will be 0. Also fix an off-by-one test against dev->num_crtcs. --- linux-core/drmP.h | 6 ++---- linux-core/drm_irq.c | 5 ++--- linux-core/i915_drv.c | 3 +-- 3 files changed, 5 insertions(+), 9 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5bc8a6c7..cf1c0fd7 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -100,10 +100,8 @@ #define DRIVER_HAVE_DMA 0x20 #define DRIVER_HAVE_IRQ 0x40 #define DRIVER_IRQ_SHARED 0x80 -#define DRIVER_IRQ_VBL 0x100 -#define DRIVER_DMA_QUEUE 0x200 -#define DRIVER_FB_DMA 0x400 -#define DRIVER_IRQ_VBL2 0x800 +#define DRIVER_DMA_QUEUE 0x100 +#define DRIVER_FB_DMA 0x200 /*@}*/ diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index f673a97c..c9d1c0d2 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -405,7 +405,7 @@ int drm_modeset_ctl(DRM_IOCTL_ARGS) } crtc = modeset.arg; - if (crtc > dev->num_crtcs) { + if (crtc >= dev->num_crtcs) { ret = -EINVAL; goto out; } @@ -474,8 +474,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; - if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? - DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) + if (crtc >= dev->num_crtcs) return -EINVAL; drm_update_vblank_count(dev, crtc); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index e7a9bfdc..e7f69e63 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -76,8 +76,7 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR | */ - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | - DRIVER_IRQ_VBL2, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .load = i915_driver_load, .firstopen = i915_driver_firstopen, .lastclose = i915_driver_lastclose, -- cgit v1.2.3 From b6610363e373c13a2e7fdee8691756e1768bdd57 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 15 Jun 2007 11:21:57 -0700 Subject: First cut at radeon support for the vblank rework. --- linux-core/radeon_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'linux-core') diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 327a6a97..39c35134 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -60,8 +60,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | - DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | - DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, + DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, .dev_priv_size = sizeof(drm_radeon_buf_priv_t), .load = radeon_driver_load, .firstopen = radeon_driver_firstopen, @@ -70,8 +69,9 @@ static struct drm_driver driver = { .postclose = radeon_driver_postclose, .lastclose = radeon_driver_lastclose, .unload = radeon_driver_unload, - .vblank_wait = radeon_driver_vblank_wait, - .vblank_wait2 = radeon_driver_vblank_wait2, + .get_vblank_counter = radeon_get_vblank_counter, + .enable_vblank = radeon_enable_vblank, + .disable_vblank = radeon_disable_vblank, .dri_library_name = dri_library_name, .irq_preinstall = radeon_driver_irq_preinstall, .irq_postinstall = radeon_driver_irq_postinstall, -- cgit v1.2.3 From 2738bca6f52e236a2d9a0e456a78b10442ededdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 22 Jun 2007 11:44:38 +0200 Subject: Use drm_calloc instead of assigning 0. --- linux-core/drm_irq.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index c9d1c0d2..01e970f9 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -105,18 +105,18 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) if (!dev->vblank_refcount) goto err; - dev->last_vblank = drm_alloc(sizeof(u32) * num_crtcs, - DRM_MEM_DRIVER); + dev->last_vblank = drm_calloc(1, sizeof(u32) * num_crtcs, + DRM_MEM_DRIVER); if (!dev->last_vblank) goto err; - dev->vblank_premodeset = drm_alloc(sizeof(u32) * num_crtcs, - DRM_MEM_DRIVER); + dev->vblank_premodeset = drm_calloc(1, sizeof(u32) * num_crtcs, + DRM_MEM_DRIVER); if (!dev->vblank_premodeset) goto err; - dev->vblank_offset = drm_alloc(sizeof(u32) * num_crtcs, - DRM_MEM_DRIVER); + dev->vblank_offset = drm_calloc(1, sizeof(u32) * num_crtcs, + DRM_MEM_DRIVER); if (!dev->vblank_offset) goto err; @@ -126,9 +126,6 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs) INIT_LIST_HEAD(&dev->vbl_sigs[i]); atomic_set(&dev->_vblank_count[i], 0); atomic_set(&dev->vblank_refcount[i], 0); - dev->last_vblank[i] = 0; - dev->vblank_premodeset[i] = 0; - dev->vblank_offset[i] = 0; } return 0; -- cgit v1.2.3 From d2d53024fb4003a6b86a3ea1ea33c76ac20bebc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 22 Jun 2007 11:45:23 +0200 Subject: Fix vblank wait condition. Sync-to-vblank actually works again for me with radeon. --- linux-core/drm_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 01e970f9..5d8d71be 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -554,7 +554,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return ret; DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, (((cur_vblank = drm_vblank_count(dev, crtc)) - - seq) <= (1 << 23))); + - vblwait.request.sequence) <= (1 << 23))); drm_vblank_put(dev, crtc); do_gettimeofday(&now); vblwait.reply.tval_sec = now.tv_sec; -- cgit v1.2.3 From 97dcd7fd25c18d5148619254229f8d94efb55b44 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 22 Jun 2007 11:06:51 -0700 Subject: more vblank rework - use a timer for disabling vblank events to avoid enable/disable calls too often - make i915 work with pre-965 chips again (would like to structure this better, but this hack works on my test system) --- linux-core/drmP.h | 1 + linux-core/drm_irq.c | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index cf1c0fd7..0ab69feb 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -832,6 +832,7 @@ typedef struct drm_device { /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ u32 *vblank_premodeset; /* were lost during modeset */ + struct timer_list vblank_disable_timer; unsigned long max_vblank_count; /**< size of vblank counter register */ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index c9d1c0d2..1e1b7f4d 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -77,10 +77,22 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, return 0; } +static void vblank_disable_fn(unsigned long arg) +{ + drm_device_t *dev = (drm_device_t *)arg; + int i; + + for (i = 0; i < dev->num_crtcs; i++) + if (atomic_read(&dev->vblank_refcount[i]) == 0) + dev->driver->disable_vblank(dev, i); +} + int drm_vblank_init(drm_device_t *dev, int num_crtcs) { int i, ret = -ENOMEM; + setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,\ + (unsigned long)dev); spin_lock_init(&dev->vbl_lock); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -377,9 +389,10 @@ EXPORT_SYMBOL(drm_vblank_get); */ void drm_vblank_put(drm_device_t *dev, int crtc) { - /* Last user can disable interrupts */ + /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) - dev->driver->disable_vblank(dev, crtc); + mod_timer(&dev->vblank_disable_timer, + round_jiffies_relative(DRM_HZ)); } EXPORT_SYMBOL(drm_vblank_put); -- cgit v1.2.3 From 7e9ea55a2f052cc939ba9bbf9edac39798344b7a Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 25 Oct 2007 17:14:53 -0700 Subject: Initial pass at porting MGA to vblank-rework This is currently only compile tested. --- linux-core/mga_drv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'linux-core') diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index ef6f1e44..6419cbdc 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -46,15 +46,16 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | - DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | - DRIVER_IRQ_VBL, + DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .dev_priv_size = sizeof (drm_mga_buf_priv_t), .load = mga_driver_load, .unload = mga_driver_unload, .lastclose = mga_driver_lastclose, .dma_quiescent = mga_driver_dma_quiescent, .device_is_agp = mga_driver_device_is_agp, - .vblank_wait = mga_driver_vblank_wait, + .get_vblank_counter = mga_get_vblank_counter, + .enable_vblank = mga_enable_vblank, + .disable_vblank = mga_disable_vblank, .irq_preinstall = mga_driver_irq_preinstall, .irq_postinstall = mga_driver_irq_postinstall, .irq_uninstall = mga_driver_irq_uninstall, -- cgit v1.2.3 From 00d60265570c866261c09fd3397d5853a1ce196a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 1 Nov 2007 12:50:03 -0700 Subject: Cleanup vblank_init and fix drm_irq_install The vblank_init function wanted a couple of cleanups. Also, drm_irq_install wasn't checking the new return value of irq_postinstall. If it returns a failure, assume IRQs didn't get set up and take appropriate action. --- linux-core/drm_irq.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index e917e7eb..4aa58d77 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -85,7 +85,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) { int i, ret = -ENOMEM; - setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,\ + setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, (unsigned long)dev); spin_lock_init(&dev->vbl_lock); atomic_set(&dev->vbl_signal_pending, 0); @@ -111,18 +111,16 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_refcount) goto err; - dev->last_vblank = drm_calloc(1, sizeof(u32) * num_crtcs, - DRM_MEM_DRIVER); + dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); if (!dev->last_vblank) goto err; - dev->vblank_premodeset = drm_calloc(1, sizeof(u32) * num_crtcs, + dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); if (!dev->vblank_premodeset) goto err; - dev->vblank_offset = drm_calloc(1, sizeof(u32) * num_crtcs, - DRM_MEM_DRIVER); + dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); if (!dev->vblank_offset) goto err; @@ -210,6 +208,11 @@ int drm_irq_install(struct drm_device * dev) /* After installing handler */ ret = dev->driver->irq_postinstall(dev); + if (ret < 0) { + mutex_lock(&dev->struct_mutex); + dev->irq_enabled = 0; + mutex_unlock(&dev->struct_mutex); + } return ret; } -- cgit v1.2.3 From b0bc5f1ae559c705565e516ebb289bf072559dec Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 11:42:17 -0800 Subject: Make ttm create/destroy APIs consistent. Pass page_flags in create. Creating a ttm was done with drm_ttm_init while destruction was done with drm_destroy_ttm. Renaming these to drm_ttm_create and drm_ttm_destroy makes their use clearer. Passing page_flags to the create function will allow that to know whether user or kernel pages are needed, with the goal of allowing kernel ttms to be saved for later reuse. --- linux-core/drm_bo.c | 8 ++++---- linux-core/drm_bo_move.c | 4 ++-- linux-core/drm_objects.h | 4 ++-- linux-core/drm_ttm.c | 16 ++++++++-------- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d308dcfd..4845f442 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -144,12 +144,12 @@ static int drm_bo_add_ttm(struct drm_buffer_object *bo) switch (bo->type) { case drm_bo_type_dc: case drm_bo_type_kernel: - bo->ttm = drm_ttm_init(dev, bo->num_pages << PAGE_SHIFT); + bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, 0); if (!bo->ttm) ret = -ENOMEM; break; case drm_bo_type_user: - bo->ttm = drm_ttm_init(dev, bo->num_pages << PAGE_SHIFT); + bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, DRM_TTM_PAGE_USER); if (!bo->ttm) ret = -ENOMEM; @@ -262,7 +262,7 @@ out_err: new_man = &bm->man[bo->mem.mem_type]; if ((new_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && bo->ttm) { drm_ttm_unbind(bo->ttm); - drm_destroy_ttm(bo->ttm); + drm_ttm_destroy(bo->ttm); bo->ttm = NULL; } @@ -419,7 +419,7 @@ static void drm_bo_destroy_locked(struct drm_buffer_object *bo) if (bo->ttm) { drm_ttm_unbind(bo->ttm); - drm_destroy_ttm(bo->ttm); + drm_ttm_destroy(bo->ttm); bo->ttm = NULL; } diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 971b4af8..00d8d3e6 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -260,7 +260,7 @@ out2: if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (ttm != NULL)) { drm_ttm_unbind(ttm); - drm_destroy_ttm(ttm); + drm_ttm_destroy(ttm); bo->ttm = NULL; } @@ -365,7 +365,7 @@ int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm != NULL)) { drm_ttm_unbind(bo->ttm); - drm_destroy_ttm(bo->ttm); + drm_ttm_destroy(bo->ttm); bo->ttm = NULL; } } else { diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 1dc61fde..66611f6d 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -297,7 +297,7 @@ struct drm_ttm { }; -extern struct drm_ttm *drm_ttm_init(struct drm_device *dev, unsigned long size); +extern struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags); extern int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem); extern void drm_ttm_unbind(struct drm_ttm *ttm); extern void drm_ttm_evict(struct drm_ttm *ttm); @@ -318,7 +318,7 @@ extern int drm_ttm_set_user(struct drm_ttm *ttm, * Otherwise it is called when the last vma exits. */ -extern int drm_destroy_ttm(struct drm_ttm *ttm); +extern int drm_ttm_destroy(struct drm_ttm *ttm); #define DRM_FLAG_MASKED(_old, _new, _mask) {\ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 3540571f..4200bc1a 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -193,7 +193,7 @@ static void drm_ttm_free_alloced_pages(struct drm_ttm *ttm) * Free all resources associated with a ttm. */ -int drm_destroy_ttm(struct drm_ttm *ttm) +int drm_ttm_destroy(struct drm_ttm *ttm) { struct drm_ttm_backend *be; @@ -251,11 +251,11 @@ int drm_ttm_set_user(struct drm_ttm *ttm, int i; BUG_ON(num_pages != ttm->num_pages); + BUG_ON((ttm->page_flags & DRM_TTM_PAGE_USER) == 0); ttm->dummy_read_page = dummy_read_page; - ttm->page_flags |= DRM_TTM_PAGE_USER | - ((write) ? DRM_TTM_PAGE_USER_WRITE : 0); - + if (write) + ttm->page_flags |= DRM_TTM_PAGE_USER_WRITE; down_read(&mm->mmap_sem); ret = get_user_pages(tsk, mm, start, num_pages, @@ -299,7 +299,7 @@ int drm_ttm_populate(struct drm_ttm *ttm) * Initialize a ttm. */ -struct drm_ttm *drm_ttm_init(struct drm_device *dev, unsigned long size) +struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags) { struct drm_bo_driver *bo_driver = dev->driver->bo_driver; struct drm_ttm *ttm; @@ -317,7 +317,7 @@ struct drm_ttm *drm_ttm_init(struct drm_device *dev, unsigned long size) ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->page_flags = 0; + ttm->page_flags = page_flags; /* * Account also for AGP module memory usage. @@ -325,13 +325,13 @@ struct drm_ttm *drm_ttm_init(struct drm_device *dev, unsigned long size) ttm_alloc_pages(ttm); if (!ttm->pages) { - drm_destroy_ttm(ttm); + drm_ttm_destroy(ttm); DRM_ERROR("Failed allocating page table\n"); return NULL; } ttm->be = bo_driver->create_ttm_backend_entry(dev); if (!ttm->be) { - drm_destroy_ttm(ttm); + drm_ttm_destroy(ttm); DRM_ERROR("Failed creating ttm backend entry\n"); return NULL; } -- cgit v1.2.3 From b5181d2506be332db8b07c02cdf37c6e25545c4d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 12:33:35 -0800 Subject: Document drm_bo_do_validate. Remove spurious 'do_wait' parameter. Add comments about the parameters to drm_bo_do_validate, along with comments for the DRM_BO_HINT options. Remove the 'do_wait' parameter as it is duplicated by DRM_BO_HINT_DONT_BLOCK. --- linux-core/drm_bo.c | 29 +++++++++++++++++++++++++---- linux-core/drm_objects.h | 1 - 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 4845f442..d7a507ab 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1502,13 +1502,36 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, return 0; } +/* + * drm_bo_do_validate + * + * 'validate' a buffer object. This changes where the buffer is + * located, along with changing access modes. + * + * flags access rights, mapping parameters and cacheability. See + * the DRM_BO_FLAG_* values in drm.h + * + * mask which flag values to change; this allows callers to modify + * things without knowing the current state of other flags. + * + * hint changes the proceedure for this operation, see the DRM_BO_HINT_* + * values in drm.h. + * + * fence_class a driver-specific way of doing fences. Presumably, this + * would be used if the driver had more than one submission and + * fencing mechanism. At this point, there isn't any use of this + * from the user mode code. + * + * rep will be stuffed with the reply from validation + */ + int drm_bo_do_validate(struct drm_buffer_object *bo, uint64_t flags, uint64_t mask, uint32_t hint, uint32_t fence_class, - int no_wait, struct drm_bo_info_rep *rep) { int ret; + int no_wait = (hint & DRM_BO_HINT_DONT_BLOCK) != 0; mutex_lock(&bo->mutex); ret = drm_bo_wait_unfenced(bo, no_wait, 0); @@ -1547,7 +1570,6 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, struct drm_device *dev = file_priv->head->dev; struct drm_buffer_object *bo; int ret; - int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(file_priv, handle, 1); @@ -1567,8 +1589,7 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, mask &= ~(DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE); - ret = drm_bo_do_validate(bo, flags, mask, hint, fence_class, - no_wait, rep); + ret = drm_bo_do_validate(bo, flags, mask, hint, fence_class, rep); if (!ret && bo_rep) *bo_rep = bo; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 66611f6d..1c6ca795 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -546,7 +546,6 @@ extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file *file_ extern int drm_bo_do_validate(struct drm_buffer_object *bo, uint64_t flags, uint64_t mask, uint32_t hint, uint32_t fence_class, - int no_wait, struct drm_bo_info_rep *rep); /* -- cgit v1.2.3 From 5f23519b14e54823c94f5db5ad81e6bd5ffd3877 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 12:45:55 -0800 Subject: Document drm_bo_handle_validate. Match drm_bo_do_validate parameter order. Document parameters and usage for drm_bo_handle_validate. Change parameter order to match drm_bo_do_validate (fence_class has been moved to after flags, hint and mask values). Existing users of this function have been changed, but out-of-tree users must be modified separately. --- linux-core/drm_bo.c | 67 ++++++++++++++++++++++++++++++++++++------------ linux-core/drm_objects.h | 5 ++-- 2 files changed, 52 insertions(+), 20 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d7a507ab..aa613d7a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1502,27 +1502,29 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, return 0; } -/* +/** * drm_bo_do_validate * - * 'validate' a buffer object. This changes where the buffer is - * located, along with changing access modes. + * @bo: the buffer object * - * flags access rights, mapping parameters and cacheability. See - * the DRM_BO_FLAG_* values in drm.h + * @flags: access rights, mapping parameters and cacheability. See + * the DRM_BO_FLAG_* values in drm.h * - * mask which flag values to change; this allows callers to modify - * things without knowing the current state of other flags. + * @mask: Which flag values to change; this allows callers to modify + * things without knowing the current state of other flags. * - * hint changes the proceedure for this operation, see the DRM_BO_HINT_* - * values in drm.h. + * @hint: changes the proceedure for this operation, see the DRM_BO_HINT_* + * values in drm.h. * - * fence_class a driver-specific way of doing fences. Presumably, this - * would be used if the driver had more than one submission and - * fencing mechanism. At this point, there isn't any use of this - * from the user mode code. + * @fence_class: a driver-specific way of doing fences. Presumably, + * this would be used if the driver had more than one submission and + * fencing mechanism. At this point, there isn't any use of this + * from the user mode code. * - * rep will be stuffed with the reply from validation + * @rep: To be stuffed with the reply from validation + * + * 'validate' a buffer object. This changes where the buffer is + * located, along with changing access modes. */ int drm_bo_do_validate(struct drm_buffer_object *bo, @@ -1558,11 +1560,42 @@ out: } EXPORT_SYMBOL(drm_bo_do_validate); +/** + * drm_bo_handle_validate + * + * @file_priv: the drm file private, used to get a handle to the user context + * + * @handle: the buffer object handle + * + * @flags: access rights, mapping parameters and cacheability. See + * the DRM_BO_FLAG_* values in drm.h + * + * @mask: Which flag values to change; this allows callers to modify + * things without knowing the current state of other flags. + * + * @hint: changes the proceedure for this operation, see the DRM_BO_HINT_* + * values in drm.h. + * + * @fence_class: a driver-specific way of doing fences. Presumably, + * this would be used if the driver had more than one submission and + * fencing mechanism. At this point, there isn't any use of this + * from the user mode code. + * + * @use_old_fence_class: don't change fence class, pull it from the buffer object + * + * @rep: To be stuffed with the reply from validation + * + * @bp_rep: To be stuffed with the buffer object pointer + * + * Perform drm_bo_do_validate on a buffer referenced by a user-space handle. + * Some permissions checking is done on the parameters, otherwise this + * is a thin wrapper. + */ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, - uint32_t fence_class, uint64_t flags, uint64_t mask, uint32_t hint, + uint32_t fence_class, int use_old_fence_class, struct drm_bo_info_rep *rep, struct drm_buffer_object **bo_rep) @@ -1818,11 +1851,11 @@ int drm_bo_setstatus_ioctl(struct drm_device *dev, if (ret) return ret; - ret = drm_bo_handle_validate(file_priv, req->handle, req->fence_class, + ret = drm_bo_handle_validate(file_priv, req->handle, req->flags, req->mask, req->hint | DRM_BO_HINT_DONT_FENCE, - 1, + req->fence_class, 1, rep, NULL); (void) drm_bo_read_unlock(&dev->bm.bm_lock); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 1c6ca795..0926b47b 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -535,9 +535,8 @@ extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type); extern int drm_bo_init_mm(struct drm_device *dev, unsigned type, unsigned long p_offset, unsigned long p_size); extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, - uint32_t fence_class, uint64_t flags, - uint64_t mask, uint32_t hint, - int use_old_fence_class, + uint64_t flags, uint64_t mask, uint32_t hint, + uint32_t fence_class, int use_old_fence_class, struct drm_bo_info_rep *rep, struct drm_buffer_object **bo_rep); extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file *file_priv, -- cgit v1.2.3 From 7461519fed25f6d63415a9dd4b915c6cc668a69c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 12:49:22 -0800 Subject: Document fence_class mess in drm_bo_setstatus_ioctl drmBOSetStatus does not bother to set the fence_class parameter. Fortunately, drm_bo_setstatus_ioctl doesn't end up using it as it calls drm_bo_handle_validate with use_old_fence_class = 1. --- linux-core/drm_bo.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index aa613d7a..1ce86978 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1851,6 +1851,12 @@ int drm_bo_setstatus_ioctl(struct drm_device *dev, if (ret) return ret; + /* + * validate the buffer. note that 'fence_class' will be unused + * as we pass use_old_fence_class=1 here. Note also that + * the libdrm API doesn't pass fence_class to the kernel, + * so it's a good thing it isn't used here. + */ ret = drm_bo_handle_validate(file_priv, req->handle, req->flags, req->mask, -- cgit v1.2.3 From 9d17373ffbba3cc4ee5f63ff02ff24d48ab99fe0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 13:19:09 -0800 Subject: Document drm_buffer_object_validate function. Just add documentation for this function, no code changes. --- linux-core/drm_bo.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1ce86978..7033a8ba 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1372,8 +1372,25 @@ static int drm_bo_mem_compat(struct drm_bo_mem_reg *mem) return 1; } -/* - * bo locked. +/** + * drm_buffer_object_validate: + * + * @bo: the buffer object to modify + * + * @fence_class: the new fence class covering this buffer + * + * @move_unfenced: a boolean indicating whether switching the + * memory space of this buffer should cause the buffer to + * be placed on the unfenced list. + * + * @no_wait: whether this function should return -EBUSY instead + * of waiting. + * + * Change buffer access parameters. This can involve moving + * the buffer to the correct memory type, pinning the buffer + * or changing the class/type of fence covering this buffer + * + * Must be called with bo locked. */ static int drm_buffer_object_validate(struct drm_buffer_object *bo, @@ -1503,7 +1520,7 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, } /** - * drm_bo_do_validate + * drm_bo_do_validate: * * @bo: the buffer object * -- cgit v1.2.3 From 0b031dbd63bbb3e0ba6d39e1e5c4eb4e87985158 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 13:19:35 -0800 Subject: Document drm_ttm_set_user. Add a comment explaining the parameters for this function --- linux-core/drm_ttm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 4200bc1a..4c1b3274 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -239,6 +239,22 @@ struct page *drm_ttm_get_page(struct drm_ttm *ttm, int index) } EXPORT_SYMBOL(drm_ttm_get_page); +/** + * drm_ttm_set_user: + * + * @ttm: the ttm to map pages to. This must always be + * a freshly created ttm. + * + * @tsk: a pointer to the address space from which to map + * pages. + * + * @write: a boolean indicating that write access is desired + * + * start: the starting address + * + * Map a range of user addresses to a new ttm object. This + * provides access to user memory from the graphics device. + */ int drm_ttm_set_user(struct drm_ttm *ttm, struct task_struct *tsk, int write, -- cgit v1.2.3 From 6d44f48002c19d67187adb660ef74dd1870d52c2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 00:54:25 -0800 Subject: Clean up and document drm_ttm.c APIs. drm_bind_ttm -> drm_ttm_bind. Aside from changing drm_bind_ttm to drm_ttm_bind, this patch adds only documentation and fixes the functions inside drm_ttm.c to all be prefixed with drm_ttm_. --- linux-core/drm_bo.c | 2 +- linux-core/drm_bo_move.c | 2 +- linux-core/drm_objects.h | 37 +++++++++++++++++++-- linux-core/drm_ttm.c | 79 ++++++++++++++++++++++++++++++++++++--------- linux-core/nouveau_buffer.c | 2 +- 5 files changed, 102 insertions(+), 20 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7033a8ba..eced94ea 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -199,7 +199,7 @@ static int drm_bo_handle_move_mem(struct drm_buffer_object *bo, goto out_err; if (mem->mem_type != DRM_BO_MEM_LOCAL) { - ret = drm_bind_ttm(bo->ttm, mem); + ret = drm_ttm_bind(bo->ttm, mem); if (ret) goto out_err; } diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 00d8d3e6..4afdfbbd 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -71,7 +71,7 @@ int drm_bo_move_ttm(struct drm_buffer_object *bo, save_flags = old_mem->flags; } if (new_mem->mem_type != DRM_BO_MEM_LOCAL) { - ret = drm_bind_ttm(ttm, new_mem); + ret = drm_ttm_bind(ttm, new_mem); if (ret) return ret; } diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 0926b47b..fa029d8e 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -298,7 +298,7 @@ struct drm_ttm { }; extern struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags); -extern int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem); +extern int drm_ttm_bind(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem); extern void drm_ttm_unbind(struct drm_ttm *ttm); extern void drm_ttm_evict(struct drm_ttm *ttm); extern void drm_ttm_fixup_caching(struct drm_ttm *ttm); @@ -331,14 +331,47 @@ extern int drm_ttm_destroy(struct drm_ttm *ttm); * Page flags. */ +/* + * This ttm should not be cached by the CPU + */ #define DRM_TTM_PAGE_UNCACHED (1 << 0) +/* + * This flat is not used at this time; I don't know what the + * intent was + */ #define DRM_TTM_PAGE_USED (1 << 1) +/* + * This flat is not used at this time; I don't know what the + * intent was + */ #define DRM_TTM_PAGE_BOUND (1 << 2) +/* + * This flat is not used at this time; I don't know what the + * intent was + */ #define DRM_TTM_PAGE_PRESENT (1 << 3) +/* + * The array of page pointers was allocated with vmalloc + * instead of drm_calloc. + */ #define DRM_TTM_PAGE_VMALLOC (1 << 4) +/* + * This ttm is mapped from user space + */ #define DRM_TTM_PAGE_USER (1 << 5) -#define DRM_TTM_PAGE_USER_WRITE (1 << 6) +/* + * This ttm will be written to by the GPU + */ +#define DRM_TTM_PAGE_USER_WRITE (1 << 6) +/* + * This ttm was mapped to the GPU, and so the contents may have + * been modified + */ #define DRM_TTM_PAGE_USER_DIRTY (1 << 7) +/* + * This flag is not used at this time; I don't know what the + * intent was. + */ #define DRM_TTM_PAGE_USER_DMA (1 << 8) /*************************************************** diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 4c1b3274..e3b9fcce 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -46,7 +46,7 @@ EXPORT_SYMBOL(drm_ttm_cache_flush); * Use kmalloc if possible. Otherwise fall back to vmalloc. */ -static void ttm_alloc_pages(struct drm_ttm *ttm) +static void drm_ttm_alloc_pages(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); ttm->pages = NULL; @@ -66,7 +66,7 @@ static void ttm_alloc_pages(struct drm_ttm *ttm) drm_free_memctl(size); } -static void ttm_free_pages(struct drm_ttm *ttm) +static void drm_ttm_free_pages(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); @@ -103,7 +103,7 @@ static struct page *drm_ttm_alloc_page(void) * for range of pages in a ttm. */ -static int drm_set_caching(struct drm_ttm *ttm, int noncached) +static int drm_ttm_set_caching(struct drm_ttm *ttm, int noncached) { int i; struct page **cur_page; @@ -208,14 +208,14 @@ int drm_ttm_destroy(struct drm_ttm *ttm) if (ttm->pages) { if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) - drm_set_caching(ttm, 0); + drm_ttm_set_caching(ttm, 0); if (ttm->page_flags & DRM_TTM_PAGE_USER) drm_ttm_free_user_pages(ttm); else drm_ttm_free_alloced_pages(ttm); - ttm_free_pages(ttm); + drm_ttm_free_pages(ttm); } drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); @@ -291,6 +291,14 @@ int drm_ttm_set_user(struct drm_ttm *ttm, return 0; } +/** + * drm_ttm_populate: + * + * @ttm: the object to allocate pages for + * + * Allocate pages for all unset page entries, then + * call the backend to create the hardware mappings + */ int drm_ttm_populate(struct drm_ttm *ttm) { struct page *page; @@ -311,8 +319,16 @@ int drm_ttm_populate(struct drm_ttm *ttm) return 0; } -/* - * Initialize a ttm. +/** + * drm_ttm_create: + * + * @dev: the drm_device + * + * @size: The size (in bytes) of the desired object + * + * @page_flags: various DRM_TTM_PAGE_* flags. See drm_object.h. + * + * Allocate and initialize a ttm, leaving it unpopulated at this time */ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags) @@ -339,7 +355,7 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint3 * Account also for AGP module memory usage. */ - ttm_alloc_pages(ttm); + drm_ttm_alloc_pages(ttm); if (!ttm->pages) { drm_ttm_destroy(ttm); DRM_ERROR("Failed allocating page table\n"); @@ -355,10 +371,15 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint3 return ttm; } -/* - * Unbind a ttm region from the aperture. +/** + * drm_ttm_evict: + * + * @ttm: the object to be unbound from the aperture. + * + * Transition a ttm from bound to evicted, where it + * isn't present in the aperture, but various caches may + * not be consistent. */ - void drm_ttm_evict(struct drm_ttm *ttm) { struct drm_ttm_backend *be = ttm->be; @@ -372,17 +393,33 @@ void drm_ttm_evict(struct drm_ttm *ttm) ttm->state = ttm_evicted; } +/** + * drm_ttm_fixup_caching: + * + * @ttm: the object to set unbound + * + * XXX this function is misnamed. Transition a ttm from evicted to + * unbound, flushing caches as appropriate. + */ void drm_ttm_fixup_caching(struct drm_ttm *ttm) { if (ttm->state == ttm_evicted) { struct drm_ttm_backend *be = ttm->be; if (be->func->needs_ub_cache_adjust(be)) - drm_set_caching(ttm, 0); + drm_ttm_set_caching(ttm, 0); ttm->state = ttm_unbound; } } +/** + * drm_ttm_unbind: + * + * @ttm: the object to unbind from the graphics device + * + * Unbind an object from the aperture. This removes the mappings + * from the graphics device and flushes caches if necessary. + */ void drm_ttm_unbind(struct drm_ttm *ttm) { if (ttm->state == ttm_bound) @@ -391,7 +428,19 @@ void drm_ttm_unbind(struct drm_ttm *ttm) drm_ttm_fixup_caching(ttm); } -int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) +/** + * drm_ttm_bind: + * + * @ttm: the ttm object to bind to the graphics device + * + * @bo_mem: the aperture memory region which will hold the object + * + * Bind a ttm object to the aperture. This ensures that the necessary + * pages are allocated, flushes CPU caches as needed and marks the + * ttm as DRM_TTM_PAGE_USER_DIRTY to indicate that it may have been + * modified by the GPU + */ +int drm_ttm_bind(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) { struct drm_bo_driver *bo_driver = ttm->dev->driver->bo_driver; int ret = 0; @@ -409,7 +458,7 @@ int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) return ret; if (ttm->state == ttm_unbound && !(bo_mem->flags & DRM_BO_FLAG_CACHED)) - drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); + drm_ttm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); else if ((bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED) && bo_driver->ttm_cache_flush) bo_driver->ttm_cache_flush(ttm); @@ -426,4 +475,4 @@ int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) ttm->page_flags |= DRM_TTM_PAGE_USER_DIRTY; return 0; } -EXPORT_SYMBOL(drm_bind_ttm); +EXPORT_SYMBOL(drm_ttm_bind); diff --git a/linux-core/nouveau_buffer.c b/linux-core/nouveau_buffer.c index 9b252a05..59751ff2 100644 --- a/linux-core/nouveau_buffer.c +++ b/linux-core/nouveau_buffer.c @@ -215,7 +215,7 @@ nouveau_bo_move_gart(struct drm_buffer_object *bo, int evict, int no_wait, if (ret) return ret; - ret = drm_bind_ttm(bo->ttm, &tmp_mem); + ret = drm_ttm_bind (bo->ttm, &tmp_mem); if (ret) goto out_cleanup; -- cgit v1.2.3 From 881ee70ab7bab5d6f6140dc9bf1e19c7b5844084 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 01:12:07 -0800 Subject: Move dummy_read_page from drm_ttm_set_user to drm_ttm_create. I'm hoping to use the dummy_read_page for kernel allocated buffers to avoid allocating extra pages for read-only buffers (like vertex and batch buffers). This also eliminates the 'write' parameter to drm_ttm_set_user and just has DRM_TTM_PAGE_WRITE passed into drm_ttm_create. --- linux-core/drm_bo.c | 15 ++++++++++----- linux-core/drm_objects.h | 10 +++++----- linux-core/drm_ttm.c | 16 +++++++--------- 3 files changed, 22 insertions(+), 19 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index eced94ea..e7b9c5b1 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -137,27 +137,32 @@ static int drm_bo_add_ttm(struct drm_buffer_object *bo) { struct drm_device *dev = bo->dev; int ret = 0; + uint32_t page_flags = 0; DRM_ASSERT_LOCKED(&bo->mutex); bo->ttm = NULL; + if (bo->mem.mask & DRM_BO_FLAG_WRITE) + page_flags |= DRM_TTM_PAGE_WRITE; + switch (bo->type) { case drm_bo_type_dc: case drm_bo_type_kernel: - bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, 0); + bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, + page_flags, dev->bm.dummy_read_page); if (!bo->ttm) ret = -ENOMEM; break; case drm_bo_type_user: - bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, DRM_TTM_PAGE_USER); + bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, + page_flags | DRM_TTM_PAGE_USER, + dev->bm.dummy_read_page); if (!bo->ttm) ret = -ENOMEM; ret = drm_ttm_set_user(bo->ttm, current, - bo->mem.mask & DRM_BO_FLAG_WRITE, bo->buffer_start, - bo->num_pages, - dev->bm.dummy_read_page); + bo->num_pages); if (ret) return ret; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index fa029d8e..375420dc 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -297,7 +297,9 @@ struct drm_ttm { }; -extern struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags); +extern struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, + uint32_t page_flags, + struct page *dummy_read_page); extern int drm_ttm_bind(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem); extern void drm_ttm_unbind(struct drm_ttm *ttm); extern void drm_ttm_evict(struct drm_ttm *ttm); @@ -307,10 +309,8 @@ extern void drm_ttm_cache_flush(void); extern int drm_ttm_populate(struct drm_ttm *ttm); extern int drm_ttm_set_user(struct drm_ttm *ttm, struct task_struct *tsk, - int write, unsigned long start, - unsigned long num_pages, - struct page *dummy_read_page); + unsigned long num_pages); /* * Destroy a ttm. The user normally calls drmRmMap or a similar IOCTL to do @@ -362,7 +362,7 @@ extern int drm_ttm_destroy(struct drm_ttm *ttm); /* * This ttm will be written to by the GPU */ -#define DRM_TTM_PAGE_USER_WRITE (1 << 6) +#define DRM_TTM_PAGE_WRITE (1 << 6) /* * This ttm was mapped to the GPU, and so the contents may have * been modified diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e3b9fcce..c1fc13fc 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -145,7 +145,7 @@ static void drm_ttm_free_user_pages(struct drm_ttm *ttm) int i; BUG_ON(!(ttm->page_flags & DRM_TTM_PAGE_USER)); - write = ((ttm->page_flags & DRM_TTM_PAGE_USER_WRITE) != 0); + write = ((ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0); dirty = ((ttm->page_flags & DRM_TTM_PAGE_USER_DIRTY) != 0); for (i = 0; i < ttm->num_pages; ++i) { @@ -257,22 +257,17 @@ EXPORT_SYMBOL(drm_ttm_get_page); */ int drm_ttm_set_user(struct drm_ttm *ttm, struct task_struct *tsk, - int write, unsigned long start, - unsigned long num_pages, - struct page *dummy_read_page) + unsigned long num_pages) { struct mm_struct *mm = tsk->mm; int ret; int i; + int write = (ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0; BUG_ON(num_pages != ttm->num_pages); BUG_ON((ttm->page_flags & DRM_TTM_PAGE_USER) == 0); - ttm->dummy_read_page = dummy_read_page; - if (write) - ttm->page_flags |= DRM_TTM_PAGE_USER_WRITE; - down_read(&mm->mmap_sem); ret = get_user_pages(tsk, mm, start, num_pages, write, 0, ttm->pages, NULL); @@ -331,7 +326,8 @@ int drm_ttm_populate(struct drm_ttm *ttm) * Allocate and initialize a ttm, leaving it unpopulated at this time */ -struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags) +struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, + uint32_t page_flags, struct page *dummy_read_page) { struct drm_bo_driver *bo_driver = dev->driver->bo_driver; struct drm_ttm *ttm; @@ -351,6 +347,8 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint3 ttm->page_flags = page_flags; + ttm->dummy_read_page = dummy_read_page; + /* * Account also for AGP module memory usage. */ -- cgit v1.2.3 From 37fb2ac4071f62bad2c36cc9ca84f9c8feee6bf5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 01:47:51 -0800 Subject: Use dummy_read_page for unpopulated kernel-allocated ttm pages. Previously, dummy_read_page was used only for read-only user allocations; it filled in pages that were not present in the user address map (presumably, these were allocated but never written to pages). This patch allows them to be used for read-only ttms allocated from the kernel, so that applications can over-allocate buffers without forcing every page to be allocated. --- linux-core/drm_agpsupport.c | 16 +++++++++++++--- linux-core/drm_objects.h | 3 ++- linux-core/drm_ttm.c | 18 +++++++----------- linux-core/nouveau_sgdma.c | 9 ++++++--- 4 files changed, 28 insertions(+), 18 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index e8bfaea4..02187017 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -505,12 +505,14 @@ static int drm_agp_needs_unbind_cache_adjust(struct drm_ttm_backend *backend) static int drm_agp_populate(struct drm_ttm_backend *backend, - unsigned long num_pages, struct page **pages) + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page) { struct drm_agp_ttm_backend *agp_be = container_of(backend, struct drm_agp_ttm_backend, backend); struct page **cur_page, **last_page = pages + num_pages; DRM_AGP_MEM *mem; + int dummy_page_count = 0; if (drm_alloc_memctl(num_pages * sizeof(void *))) return -1; @@ -528,8 +530,16 @@ static int drm_agp_populate(struct drm_ttm_backend *backend, DRM_DEBUG("Current page count is %ld\n", (long) mem->page_count); mem->page_count = 0; - for (cur_page = pages; cur_page < last_page; ++cur_page) - mem->memory[mem->page_count++] = phys_to_gart(page_to_phys(*cur_page)); + for (cur_page = pages; cur_page < last_page; ++cur_page) { + struct page *page = *cur_page; + if (!page) { + page = dummy_read_page; + ++dummy_page_count; + } + mem->memory[mem->page_count++] = phys_to_gart(page_to_phys(page)); + } + if (dummy_page_count) + DRM_DEBUG("Mapped %d dummy pages\n", dummy_page_count); agp_be->mem = mem; return 0; } diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 375420dc..47b6b018 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -263,7 +263,8 @@ struct drm_ttm_backend; struct drm_ttm_backend_func { int (*needs_ub_cache_adjust) (struct drm_ttm_backend *backend); int (*populate) (struct drm_ttm_backend *backend, - unsigned long num_pages, struct page **pages); + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page); void (*clear) (struct drm_ttm_backend *backend); int (*bind) (struct drm_ttm_backend *backend, struct drm_bo_mem_reg *bo_mem); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index c1fc13fc..a9d87338 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -262,7 +262,6 @@ int drm_ttm_set_user(struct drm_ttm *ttm, { struct mm_struct *mm = tsk->mm; int ret; - int i; int write = (ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0; BUG_ON(num_pages != ttm->num_pages); @@ -278,11 +277,6 @@ int drm_ttm_set_user(struct drm_ttm *ttm, return -ENOMEM; } - for (i = 0; i < num_pages; ++i) { - if (ttm->pages[i] == NULL) - ttm->pages[i] = ttm->dummy_read_page; - } - return 0; } @@ -304,12 +298,14 @@ int drm_ttm_populate(struct drm_ttm *ttm) return 0; be = ttm->be; - for (i = 0; i < ttm->num_pages; ++i) { - page = drm_ttm_get_page(ttm, i); - if (!page) - return -ENOMEM; + if (ttm->page_flags & DRM_TTM_PAGE_WRITE) { + for (i = 0; i < ttm->num_pages; ++i) { + page = drm_ttm_get_page(ttm, i); + if (!page) + return -ENOMEM; + } } - be->func->populate(be, ttm->num_pages, ttm->pages); + be->func->populate(be, ttm->num_pages, ttm->pages, ttm->dummy_read_page); ttm->state = ttm_unbound; return 0; } diff --git a/linux-core/nouveau_sgdma.c b/linux-core/nouveau_sgdma.c index f3bf5341..6c61819f 100644 --- a/linux-core/nouveau_sgdma.c +++ b/linux-core/nouveau_sgdma.c @@ -25,7 +25,7 @@ nouveau_sgdma_needs_ub_cache_adjust(struct drm_ttm_backend *be) static int nouveau_sgdma_populate(struct drm_ttm_backend *be, unsigned long num_pages, - struct page **pages) + struct page **pages, struct page *dummy_read_page) { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; int p, d, o; @@ -41,8 +41,11 @@ nouveau_sgdma_populate(struct drm_ttm_backend *be, unsigned long num_pages, nvbe->pages_populated = d = 0; for (p = 0; p < num_pages; p++) { for (o = 0; o < PAGE_SIZE; o += NV_CTXDMA_PAGE_SIZE) { + struct page *page = pages[p]; + if (!page) + page = dummy_read_page; nvbe->pagelist[d] = pci_map_page(nvbe->dev->pdev, - pages[p], o, + page, o, NV_CTXDMA_PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(nvbe->pagelist[d])) { @@ -299,7 +302,7 @@ nouveau_sgdma_nottm_hack_init(struct drm_device *dev) } dev_priv->gart_info.sg_handle = sgreq.handle; - if ((ret = be->func->populate(be, dev->sg->pages, dev->sg->pagelist))) { + if ((ret = be->func->populate(be, dev->sg->pages, dev->sg->pagelist, dev->bm.dummy_read_page))) { DRM_ERROR("failed populate: %d\n", ret); return ret; } -- cgit v1.2.3 From d1187641d64f442968a3b9ea6a19de6cdd45acd4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 20:16:50 -0800 Subject: Rename inappropriately named 'mask' fields to 'proposed_flags' instead. Flags pending validation were stored in a misleadingly named field, 'mask'. As 'mask' is already used to indicate pieces of a flags field which are changing, it seems better to use a name reflecting the actual purpose of this field. I chose 'proposed_flags' as they may not actually end up in 'flags', and in an case will be modified when they are moved over. This affects the API, but not ABI of the user-mode interface. --- linux-core/drm_bo.c | 111 ++++++++++++++++++++++++++------------------ linux-core/drm_bo_move.c | 12 ++--- linux-core/drm_objects.h | 45 ++++++++++++++++-- linux-core/drm_vm.c | 4 +- linux-core/i915_buffer.c | 15 ++++-- linux-core/i915_drv.c | 4 +- linux-core/nouveau_buffer.c | 13 +++--- linux-core/via_buffer.c | 2 +- 8 files changed, 139 insertions(+), 67 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e7b9c5b1..171c074a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -80,7 +80,7 @@ void drm_bo_add_to_lru(struct drm_buffer_object *bo) DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); - if (!(bo->mem.mask & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT)) + if (!(bo->mem.proposed_flags & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT)) || bo->mem.mem_type != bo->pinned_mem_type) { man = &bo->dev->bm.man[bo->mem.mem_type]; list_add_tail(&bo->lru, &man->lru); @@ -142,7 +142,7 @@ static int drm_bo_add_ttm(struct drm_buffer_object *bo) DRM_ASSERT_LOCKED(&bo->mutex); bo->ttm = NULL; - if (bo->mem.mask & DRM_BO_FLAG_WRITE) + if (bo->mem.proposed_flags & DRM_BO_FLAG_WRITE) page_flags |= DRM_TTM_PAGE_WRITE; switch (bo->type) { @@ -214,11 +214,11 @@ static int drm_bo_handle_move_mem(struct drm_buffer_object *bo, struct drm_bo_mem_reg *old_mem = &bo->mem; uint64_t save_flags = old_mem->flags; - uint64_t save_mask = old_mem->mask; + uint64_t save_proposed_flags = old_mem->proposed_flags; *old_mem = *mem; mem->mm_node = NULL; - old_mem->mask = save_mask; + old_mem->proposed_flags = save_proposed_flags; DRM_FLAG_MASKED(save_flags, mem->flags, DRM_BO_MASK_MEMTYPE); } else if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && @@ -708,7 +708,7 @@ static int drm_bo_evict(struct drm_buffer_object *bo, unsigned mem_type, evict_mem.mm_node = NULL; evict_mem = bo->mem; - evict_mem.mask = dev->driver->bo_driver->evict_mask(bo); + evict_mem.proposed_flags = dev->driver->bo_driver->evict_flags(bo); ret = drm_bo_mem_space(bo, &evict_mem, no_wait); if (ret) { @@ -872,7 +872,7 @@ int drm_bo_mem_space(struct drm_buffer_object *bo, type_ok = drm_bo_mt_compatible(man, bo->type == drm_bo_type_user, - mem_type, mem->mask, + mem_type, mem->proposed_flags, &cur_flags); if (!type_ok) @@ -924,7 +924,7 @@ int drm_bo_mem_space(struct drm_buffer_object *bo, if (!drm_bo_mt_compatible(man, bo->type == drm_bo_type_user, mem_type, - mem->mask, + mem->proposed_flags, &cur_flags)) continue; @@ -944,11 +944,25 @@ int drm_bo_mem_space(struct drm_buffer_object *bo, } EXPORT_SYMBOL(drm_bo_mem_space); -static int drm_bo_new_mask(struct drm_buffer_object *bo, - uint64_t new_flags, uint64_t used_mask) +/* + * drm_bo_propose_flags: + * + * @bo: the buffer object getting new flags + * + * @new_flags: the new set of proposed flag bits + * + * @new_mask: the mask of bits changed in new_flags + * + * Modify the proposed_flag bits in @bo + */ +static int drm_bo_modify_proposed_flags (struct drm_buffer_object *bo, + uint64_t new_flags, uint64_t new_mask) { - uint32_t new_props; + uint32_t new_access; + /* Copy unchanging bits from existing proposed_flags */ + DRM_FLAG_MASKED(new_flags, bo->mem.proposed_flags, ~new_mask); + if (bo->type == drm_bo_type_user && ((new_flags & (DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING)) != (DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING))) { @@ -956,7 +970,7 @@ static int drm_bo_new_mask(struct drm_buffer_object *bo, return -EINVAL; } - if ((used_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged processes.\n"); return -EPERM; } @@ -966,15 +980,15 @@ static int drm_bo_new_mask(struct drm_buffer_object *bo, return -EPERM; } - new_props = new_flags & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_READ); + new_access = new_flags & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_READ); - if (!new_props) { + if (new_access == 0) { DRM_ERROR("Invalid buffer object rwx properties\n"); return -EINVAL; } - bo->mem.mask = new_flags; + bo->mem.proposed_flags = new_flags; return 0; } @@ -1109,8 +1123,8 @@ static int drm_bo_wait_unfenced(struct drm_buffer_object *bo, int no_wait, ret = 0; mutex_unlock(&bo->mutex); - DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, - !drm_bo_check_unfenced(bo)); + DRM_WAIT_ON (ret, bo->event_queue, 3 * DRM_HZ, + !drm_bo_check_unfenced(bo)); mutex_lock(&bo->mutex); if (ret == -EINTR) return -EAGAIN; @@ -1146,7 +1160,7 @@ static void drm_bo_fill_rep_arg(struct drm_buffer_object *bo, else rep->arg_handle = 0; - rep->mask = bo->mem.mask; + rep->proposed_flags = bo->mem.proposed_flags; rep->buffer_start = bo->buffer_start; rep->fence_flags = bo->fence_type; rep->rep_flags = 0; @@ -1292,7 +1306,7 @@ static void drm_buffer_user_object_unmap(struct drm_file *file_priv, /* * bo->mutex locked. - * Note that new_mem_flags are NOT transferred to the bo->mem.mask. + * Note that new_mem_flags are NOT transferred to the bo->mem.proposed_flags. */ int drm_bo_move_buffer(struct drm_buffer_object *bo, uint64_t new_mem_flags, @@ -1318,7 +1332,7 @@ int drm_bo_move_buffer(struct drm_buffer_object *bo, uint64_t new_mem_flags, mem.num_pages = bo->num_pages; mem.size = mem.num_pages << PAGE_SHIFT; - mem.mask = new_mem_flags; + mem.proposed_flags = new_mem_flags; mem.page_alignment = bo->mem.page_alignment; mutex_lock(&bm->evict_mutex); @@ -1361,18 +1375,18 @@ out_unlock: static int drm_bo_mem_compat(struct drm_bo_mem_reg *mem) { - uint32_t flag_diff = (mem->mask ^ mem->flags); + uint32_t flag_diff = (mem->proposed_flags ^ mem->flags); - if ((mem->mask & mem->flags & DRM_BO_MASK_MEM) == 0) + if ((mem->proposed_flags & mem->flags & DRM_BO_MASK_MEM) == 0) return 0; if ((flag_diff & DRM_BO_FLAG_CACHED) && - (/* !(mem->mask & DRM_BO_FLAG_CACHED) ||*/ - (mem->mask & DRM_BO_FLAG_FORCE_CACHING))) + (/* !(mem->proposed_flags & DRM_BO_FLAG_CACHED) ||*/ + (mem->proposed_flags & DRM_BO_FLAG_FORCE_CACHING))) return 0; if ((flag_diff & DRM_BO_FLAG_MAPPABLE) && - ((mem->mask & DRM_BO_FLAG_MAPPABLE) || - (mem->mask & DRM_BO_FLAG_FORCE_MAPPABLE))) + ((mem->proposed_flags & DRM_BO_FLAG_MAPPABLE) || + (mem->proposed_flags & DRM_BO_FLAG_FORCE_MAPPABLE))) return 0; return 1; } @@ -1408,8 +1422,8 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, uint32_t ftype; int ret; - DRM_DEBUG("New flags 0x%016llx, Old flags 0x%016llx\n", - (unsigned long long) bo->mem.mask, + DRM_DEBUG("Proposed flags 0x%016llx, Old flags 0x%016llx\n", + (unsigned long long) bo->mem.proposed_flags, (unsigned long long) bo->mem.flags); ret = driver->fence_type(bo, &fence_class, &ftype); @@ -1450,7 +1464,7 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, */ if (!drm_bo_mem_compat(&bo->mem)) { - ret = drm_bo_move_buffer(bo, bo->mem.mask, no_wait, + ret = drm_bo_move_buffer(bo, bo->mem.proposed_flags, no_wait, move_unfenced); if (ret) { if (ret != -EAGAIN) @@ -1463,7 +1477,7 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, * Pinned buffers. */ - if (bo->mem.mask & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { + if (bo->mem.proposed_flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { bo->pinned_mem_type = bo->mem.mem_type; mutex_lock(&dev->struct_mutex); list_del_init(&bo->pinned_lru); @@ -1499,7 +1513,13 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, if (ret) return ret; } - DRM_FLAG_MASKED(bo->mem.flags, bo->mem.mask, ~DRM_BO_MASK_MEMTYPE); + /* + * Validation has succeeded, move the access and other + * non-mapping-related flag bits from the proposed flags to + * the active flags + */ + + DRM_FLAG_MASKED(bo->mem.flags, bo->mem.proposed_flags, ~DRM_BO_MASK_MEMTYPE); /* * Finally, adjust lru to be sure. @@ -1563,9 +1583,7 @@ int drm_bo_do_validate(struct drm_buffer_object *bo, if (ret) goto out; - - DRM_FLAG_MASKED(flags, bo->mem.mask, ~mask); - ret = drm_bo_new_mask(bo, flags, mask); + ret = drm_bo_modify_proposed_flags (bo, flags, mask); if (ret) goto out; @@ -1712,7 +1730,7 @@ out: int drm_buffer_object_create(struct drm_device *dev, unsigned long size, enum drm_bo_type type, - uint64_t mask, + uint64_t flags, uint32_t hint, uint32_t page_alignment, unsigned long buffer_start, @@ -1757,12 +1775,14 @@ int drm_buffer_object_create(struct drm_device *dev, bo->mem.page_alignment = page_alignment; bo->buffer_start = buffer_start & PAGE_MASK; bo->priv_flags = 0; - bo->mem.flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED | - DRM_BO_FLAG_MAPPABLE; - bo->mem.mask = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED | - DRM_BO_FLAG_MAPPABLE; + bo->mem.flags = (DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED | + DRM_BO_FLAG_MAPPABLE); + bo->mem.proposed_flags = 0; atomic_inc(&bm->count); - ret = drm_bo_new_mask(bo, mask, mask); + /* + * Use drm_bo_modify_proposed_flags to error-check the proposed flags + */ + ret = drm_bo_modify_proposed_flags (bo, flags, flags); if (ret) goto out_err; @@ -1831,18 +1851,21 @@ int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fil bo_type = (req->buffer_start) ? drm_bo_type_user : drm_bo_type_dc; + /* + * User buffers cannot be shared + */ if (bo_type == drm_bo_type_user) - req->mask &= ~DRM_BO_FLAG_SHAREABLE; + req->flags &= ~DRM_BO_FLAG_SHAREABLE; ret = drm_buffer_object_create(file_priv->head->dev, - req->size, bo_type, req->mask, + req->size, bo_type, req->flags, req->hint, req->page_alignment, req->buffer_start, &entry); if (ret) goto out; ret = drm_bo_add_user_object(file_priv, entry, - req->mask & DRM_BO_FLAG_SHAREABLE); + req->flags & DRM_BO_FLAG_SHAREABLE); if (ret) { drm_bo_usage_deref_unlocked(&entry); goto out; @@ -2034,7 +2057,7 @@ static int drm_bo_leave_list(struct drm_buffer_object *bo, DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " "cleanup. Removing flag and evicting.\n"); bo->mem.flags &= ~DRM_BO_FLAG_NO_EVICT; - bo->mem.mask &= ~DRM_BO_FLAG_NO_EVICT; + bo->mem.proposed_flags &= ~DRM_BO_FLAG_NO_EVICT; } if (bo->mem.mem_type == mem_type) diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 4afdfbbd..b06a09f0 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -54,7 +54,7 @@ int drm_bo_move_ttm(struct drm_buffer_object *bo, struct drm_ttm *ttm = bo->ttm; struct drm_bo_mem_reg *old_mem = &bo->mem; uint64_t save_flags = old_mem->flags; - uint64_t save_mask = old_mem->mask; + uint64_t save_proposed_flags = old_mem->proposed_flags; int ret; if (old_mem->mem_type == DRM_BO_MEM_TT) { @@ -78,7 +78,7 @@ int drm_bo_move_ttm(struct drm_buffer_object *bo, *old_mem = *new_mem; new_mem->mm_node = NULL; - old_mem->mask = save_mask; + old_mem->proposed_flags = save_proposed_flags; DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); return 0; } @@ -210,7 +210,7 @@ int drm_bo_move_memcpy(struct drm_buffer_object *bo, void *new_iomap; int ret; uint64_t save_flags = old_mem->flags; - uint64_t save_mask = old_mem->mask; + uint64_t save_proposed_flags = old_mem->proposed_flags; unsigned long i; unsigned long page; unsigned long add = 0; @@ -255,7 +255,7 @@ out2: *old_mem = *new_mem; new_mem->mm_node = NULL; - old_mem->mask = save_mask; + old_mem->proposed_flags = save_proposed_flags; DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (ttm != NULL)) { @@ -330,7 +330,7 @@ int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, struct drm_bo_mem_reg *old_mem = &bo->mem; int ret; uint64_t save_flags = old_mem->flags; - uint64_t save_mask = old_mem->mask; + uint64_t save_proposed_flags = old_mem->proposed_flags; struct drm_buffer_object *old_obj; if (bo->fence) @@ -399,7 +399,7 @@ int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, *old_mem = *new_mem; new_mem->mm_node = NULL; - old_mem->mask = save_mask; + old_mem->proposed_flags = save_proposed_flags; DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); return 0; } diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 47b6b018..98421e4c 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -385,8 +385,20 @@ struct drm_bo_mem_reg { unsigned long num_pages; uint32_t page_alignment; uint32_t mem_type; + /* + * Current buffer status flags, indicating + * where the buffer is located and which + * access modes are in effect + */ uint64_t flags; - uint64_t mask; + /** + * These are the flags proposed for + * a validate operation. If the + * validate succeeds, they'll get moved + * into the flags field + */ + uint64_t proposed_flags; + uint32_t desired_tile_stride; uint32_t hw_tile_stride; }; @@ -511,9 +523,36 @@ struct drm_bo_driver { int (*invalidate_caches) (struct drm_device *dev, uint64_t flags); int (*init_mem_type) (struct drm_device *dev, uint32_t type, struct drm_mem_type_manager *man); - uint32_t(*evict_mask) (struct drm_buffer_object *bo); + /* + * evict_flags: + * + * @bo: the buffer object to be evicted + * + * Return the bo flags for a buffer which is not mapped to the hardware. + * These will be placed in proposed_flags so that when the move is + * finished, they'll end up in bo->mem.flags + */ + uint64_t(*evict_flags) (struct drm_buffer_object *bo); + /* + * move: + * + * @bo: the buffer to move + * + * @evict: whether this motion is evicting the buffer from + * the graphics address space + * + * @no_wait: whether this should give up and return -EBUSY + * if this move would require sleeping + * + * @new_mem: the new memory region receiving the buffer + * + * Move a buffer between two memory regions. + */ int (*move) (struct drm_buffer_object *bo, int evict, int no_wait, struct drm_bo_mem_reg *new_mem); + /* + * ttm_cache_flush + */ void (*ttm_cache_flush)(struct drm_ttm *ttm); }; @@ -554,7 +593,7 @@ extern int drm_fence_buffer_objects(struct drm_device *dev, struct drm_fence_object **used_fence); extern void drm_bo_add_to_lru(struct drm_buffer_object *bo); extern int drm_buffer_object_create(struct drm_device *dev, unsigned long size, - enum drm_bo_type type, uint64_t mask, + enum drm_bo_type type, uint64_t flags, uint32_t hint, uint32_t page_alignment, unsigned long buffer_start, struct drm_buffer_object **bo); diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index f2681cc9..dcefcb34 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -751,10 +751,10 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, */ if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) { - uint32_t new_mask = bo->mem.mask | + uint32_t new_flags = bo->mem.proposed_flags | DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_FORCE_MAPPABLE; - err = drm_bo_move_buffer(bo, new_mask, 0, 0); + err = drm_bo_move_buffer(bo, new_flags, 0, 0); if (err) { ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT; goto out_unlock; diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index b000a725..3dd236dd 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -38,11 +38,11 @@ struct drm_ttm_backend *i915_create_ttm_backend_entry(struct drm_device *dev) return drm_agp_init_ttm(dev); } -int i915_fence_types(struct drm_buffer_object *bo, +int i915_fence_type(struct drm_buffer_object *bo, uint32_t *fclass, uint32_t *type) { - if (bo->mem.mask & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) + if (bo->mem.proposed_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) *type = 3; else *type = 1; @@ -110,7 +110,16 @@ int i915_init_mem_type(struct drm_device *dev, uint32_t type, return 0; } -uint32_t i915_evict_mask(struct drm_buffer_object *bo) +/* + * i915_evict_flags: + * + * @bo: the buffer object to be evicted + * + * Return the bo flags for a buffer which is not mapped to the hardware. + * These will be placed in proposed_flags so that when the move is + * finished, they'll end up in bo->mem.flags + */ +uint64_t i915_evict_flags(struct drm_buffer_object *bo) { switch (bo->mem.mem_type) { case DRM_BO_MEM_LOCAL: diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index d2bcf4b5..d3a4ab35 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -61,10 +61,10 @@ static struct drm_bo_driver i915_bo_driver = { .num_mem_type_prio = sizeof(i915_mem_prios)/sizeof(uint32_t), .num_mem_busy_prio = sizeof(i915_busy_prios)/sizeof(uint32_t), .create_ttm_backend_entry = i915_create_ttm_backend_entry, - .fence_type = i915_fence_types, + .fence_type = i915_fence_type, .invalidate_caches = i915_invalidate_caches, .init_mem_type = i915_init_mem_type, - .evict_mask = i915_evict_mask, + .evict_flags = i915_evict_flags, .move = i915_move, .ttm_cache_flush = i915_flush_ttm, }; diff --git a/linux-core/nouveau_buffer.c b/linux-core/nouveau_buffer.c index 59751ff2..a652bb1d 100644 --- a/linux-core/nouveau_buffer.c +++ b/linux-core/nouveau_buffer.c @@ -56,7 +56,7 @@ nouveau_bo_fence_type(struct drm_buffer_object *bo, { /* When we get called, *fclass is set to the requested fence class */ - if (bo->mem.mask & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) + if (bo->mem.proposed_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) *type = 3; else *type = 1; @@ -130,8 +130,8 @@ nouveau_bo_init_mem_type(struct drm_device *dev, uint32_t type, return 0; } -static uint32_t -nouveau_bo_evict_mask(struct drm_buffer_object *bo) +static uint64_t +nouveau_bo_evict_flags(struct drm_buffer_object *bo) { switch (bo->mem.mem_type) { case DRM_BO_MEM_LOCAL: @@ -207,8 +207,9 @@ nouveau_bo_move_gart(struct drm_buffer_object *bo, int evict, int no_wait, tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - tmp_mem.mask = DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING; + tmp_mem.proposed_flags = (DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_CACHED | + DRM_BO_FLAG_FORCE_CACHING); ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); @@ -291,7 +292,7 @@ struct drm_bo_driver nouveau_bo_driver = { .fence_type = nouveau_bo_fence_type, .invalidate_caches = nouveau_bo_invalidate_caches, .init_mem_type = nouveau_bo_init_mem_type, - .evict_mask = nouveau_bo_evict_mask, + .evict_flags = nouveau_bo_evict_flags, .move = nouveau_bo_move, .ttm_cache_flush= nouveau_bo_flush_ttm }; diff --git a/linux-core/via_buffer.c b/linux-core/via_buffer.c index ea755247..532fae6a 100644 --- a/linux-core/via_buffer.c +++ b/linux-core/via_buffer.c @@ -144,7 +144,7 @@ int via_init_mem_type(struct drm_device * dev, uint32_t type, return 0; } -uint32_t via_evict_mask(struct drm_buffer_object *bo) +uint64_t via_evict_flags(struct drm_buffer_object *bo) { switch (bo->mem.mem_type) { case DRM_BO_MEM_LOCAL: -- cgit v1.2.3 From da3601e43ae75695f3b080904b1e090c8eb1cd8e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 22:00:45 -0800 Subject: Change drm_bo_type_dc to drm_bo_type_device and comment usage of this value. I couldn't figure out what drm_bo_type_dc was for; Dave Airlie finally clued me in that it was the 'normal' buffer objects with kernel allocated pages that could be mmapped from the drm device file. I thought that 'drm_bo_type_device' was a more descriptive name. I also added a bunch of comments describing the use of the type enum values and the functions that use them. --- linux-core/drm_bo.c | 43 ++++++++++++++++++++++++++++++++++++++----- linux-core/drm_objects.h | 26 ++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 7 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 171c074a..df10e12b 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -146,7 +146,7 @@ static int drm_bo_add_ttm(struct drm_buffer_object *bo) page_flags |= DRM_TTM_PAGE_WRITE; switch (bo->type) { - case drm_bo_type_dc: + case drm_bo_type_device: case drm_bo_type_kernel: bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, page_flags, dev->bm.dummy_read_page); @@ -1155,7 +1155,12 @@ static void drm_bo_fill_rep_arg(struct drm_buffer_object *bo, rep->size = bo->num_pages * PAGE_SIZE; rep->offset = bo->offset; - if (bo->type == drm_bo_type_dc) + /* + * drm_bo_type_device buffers have user-visible + * handles which can be used to share across + * processes. Hand that back to the application + */ + if (bo->type == drm_bo_type_device) rep->arg_handle = bo->map_list.user_token; else rep->arg_handle = 0; @@ -1786,7 +1791,12 @@ int drm_buffer_object_create(struct drm_device *dev, if (ret) goto out_err; - if (bo->type == drm_bo_type_dc) { + /* + * For drm_bo_type_device buffers, allocate + * address space from the device so that applications + * can mmap the buffer from there + */ + if (bo->type == drm_bo_type_device) { mutex_lock(&dev->struct_mutex); ret = drm_bo_setup_vm_locked(bo); mutex_unlock(&dev->struct_mutex); @@ -1849,7 +1859,12 @@ int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fil return -EINVAL; } - bo_type = (req->buffer_start) ? drm_bo_type_user : drm_bo_type_dc; + /* + * If the buffer creation request comes in with a starting address, + * that points at the desired user pages to map. Otherwise, create + * a drm_bo_type_device buffer, which uses pages allocated from the kernel + */ + bo_type = (req->buffer_start) ? drm_bo_type_user : drm_bo_type_device; /* * User buffers cannot be shared @@ -2607,6 +2622,14 @@ void drm_bo_unmap_virtual(struct drm_buffer_object *bo) unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); } +/** + * drm_bo_takedown_vm_locked: + * + * @bo: the buffer object to remove any drm device mapping + * + * Remove any associated vm mapping on the drm device node that + * would have been created for a drm_bo_type_device buffer + */ static void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo) { struct drm_map_list *list; @@ -2614,7 +2637,7 @@ static void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo) struct drm_device *dev = bo->dev; DRM_ASSERT_LOCKED(&dev->struct_mutex); - if (bo->type != drm_bo_type_dc) + if (bo->type != drm_bo_type_device) return; list = &bo->map_list; @@ -2637,6 +2660,16 @@ static void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo) drm_bo_usage_deref_locked(&bo); } +/** + * drm_bo_setup_vm_locked: + * + * @bo: the buffer to allocate address space for + * + * Allocate address space in the drm device so that applications + * can mmap the buffer and access the contents. This only + * applies to drm_bo_type_device objects as others are not + * placed in the drm device address space. + */ static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo) { struct drm_map_list *list = &bo->map_list; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 98421e4c..a2d10b5d 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -404,9 +404,31 @@ struct drm_bo_mem_reg { }; enum drm_bo_type { - drm_bo_type_dc, + /* + * drm_bo_type_device are 'normal' drm allocations, + * pages are allocated from within the kernel automatically + * and the objects can be mmap'd from the drm device. Each + * drm_bo_type_device object has a unique name which can be + * used by other processes to share access to the underlying + * buffer. + */ + drm_bo_type_device, + /* + * drm_bo_type_user are buffers of pages that already exist + * in the process address space. They are more limited than + * drm_bo_type_device buffers in that they must always + * remain cached (as we assume the user pages are mapped cached), + * and they are not sharable to other processes through DRM + * (although, regular shared memory should still work fine). + */ drm_bo_type_user, - drm_bo_type_kernel, /* for initial kernel allocations */ + /* + * drm_bo_type_kernel are buffers that exist solely for use + * within the kernel. The pages cannot be mapped into the + * process. One obvious use would be for the ring + * buffer where user access would not (ideally) be required. + */ + drm_bo_type_kernel, }; struct drm_buffer_object { -- cgit v1.2.3 From 5d8d64ad3881c10bc3cd3fd5cab1ac14268da5ce Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Tue, 25 Dec 2007 16:57:14 +0800 Subject: i915: i915_execbuffer ioctl32 routine, fix #13732 --- linux-core/i915_ioc32.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/i915_ioc32.c b/linux-core/i915_ioc32.c index 11dee035..b878e21c 100644 --- a/linux-core/i915_ioc32.c +++ b/linux-core/i915_ioc32.c @@ -34,6 +34,7 @@ #include "drmP.h" #include "drm.h" #include "i915_drm.h" +#include "i915_drv.h" typedef struct _drm_i915_batchbuffer32 { int start; /* agp offset */ @@ -182,13 +183,55 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd, DRM_IOCTL_I915_ALLOC, (unsigned long) request); } +typedef struct drm_i915_execbuffer32 { + uint64_t ops_list; + uint32_t num_buffers; + struct _drm_i915_batchbuffer32 batch; + drm_context_t context; + struct drm_fence_arg fence_arg; +} drm_i915_execbuffer32_t; + +static int compat_i915_execbuffer(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_execbuffer32_t req32; + struct drm_i915_execbuffer __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.ops_list, &request->ops_list) + || __put_user(req32.num_buffers, &request->num_buffers) + || __put_user(req32.context, &request->context) + || __copy_to_user(&request->fence_arg, &req32.fence_arg, + sizeof(req32.fence_arg)) + || __put_user(req32.batch.start, &request->batch.start) + || __put_user(req32.batch.used, &request->batch.used) + || __put_user(req32.batch.DR1, &request->batch.DR1) + || __put_user(req32.batch.DR4, &request->batch.DR4) + || __put_user(req32.batch.num_cliprects, + &request->batch.num_cliprects) + || __put_user((int __user *)(unsigned long)req32.batch.cliprects, + &request->batch.cliprects)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_I915_EXECBUFFER, (unsigned long)request); +} + drm_ioctl_compat_t *i915_compat_ioctls[] = { [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer, [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer, [DRM_I915_GETPARAM] = compat_i915_getparam, [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit, - [DRM_I915_ALLOC] = compat_i915_alloc + [DRM_I915_ALLOC] = compat_i915_alloc, +#ifdef I915_HAVE_BUFFER + [DRM_I915_EXECBUFFER] = compat_i915_execbuffer, +#endif }; /** -- cgit v1.2.3 From b9417f41418321d5081547a3a3386dcccae7541f Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Wed, 26 Dec 2007 17:13:58 +0800 Subject: i915: return fence argument from i915_execbuffer ioctl32 routine --- linux-core/i915_ioc32.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/i915_ioc32.c b/linux-core/i915_ioc32.c index b878e21c..0b8fff19 100644 --- a/linux-core/i915_ioc32.c +++ b/linux-core/i915_ioc32.c @@ -196,6 +196,7 @@ static int compat_i915_execbuffer(struct file *file, unsigned int cmd, { drm_i915_execbuffer32_t req32; struct drm_i915_execbuffer __user *request; + int err; if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) return -EFAULT; @@ -218,8 +219,25 @@ static int compat_i915_execbuffer(struct file *file, unsigned int cmd, &request->batch.cliprects)) return -EFAULT; - return drm_ioctl(file->f_dentry->d_inode, file, + err = drm_ioctl(file->f_dentry->d_inode, file, DRM_IOCTL_I915_EXECBUFFER, (unsigned long)request); + + if (err) + return err; + + if (__get_user(req32.fence_arg.handle, &request->fence_arg.handle) + || __get_user(req32.fence_arg.fence_class, &request->fence_arg.fence_class) + || __get_user(req32.fence_arg.type, &request->fence_arg.type) + || __get_user(req32.fence_arg.flags, &request->fence_arg.flags) + || __get_user(req32.fence_arg.signaled, &request->fence_arg.signaled) + || __get_user(req32.fence_arg.error, &request->fence_arg.error) + || __get_user(req32.fence_arg.sequence, &request->fence_arg.sequence)) + return -EFAULT; + + if (copy_to_user((void __user *)arg, &req32, sizeof(req32))) + return -EFAULT; + + return 0; } -- cgit v1.2.3 From 9ab620d661253f9b08f683a2a6f9ddee002015bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Thu, 3 Jan 2008 16:56:04 +1000 Subject: drm: cleanup DRM_DEBUG() parameters As DRM_DEBUG macro already prints out the __FUNCTION__ string (see drivers/char/drm/drmP.h), it is not worth doing this again. At some other places the ending "\n" was added. airlied:- I cleaned up a few that this patch missed also --- linux-core/ati_pcigart.c | 6 +++--- linux-core/drm_irq.c | 4 ++-- linux-core/drm_scatter.c | 10 +++++----- linux-core/drm_vm.c | 4 ++-- linux-core/i810_dma.c | 22 ++++++++-------------- linux-core/i810_drv.h | 2 +- linux-core/sis_mm.c | 4 ++-- linux-core/via_mm.c | 4 ++-- 8 files changed, 25 insertions(+), 31 deletions(-) (limited to 'linux-core') diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index e6187365..68029635 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -41,7 +41,7 @@ static void *drm_ati_alloc_pcigart_table(int order) struct page *page; int i; - DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order); + DRM_DEBUG("%d order\n", order); address = __get_free_pages(GFP_KERNEL | __GFP_COMP, order); @@ -58,7 +58,7 @@ static void *drm_ati_alloc_pcigart_table(int order) SetPageReserved(page); } - DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); + DRM_DEBUG("returning 0x%08lx\n", address); return (void *)address; } @@ -67,7 +67,7 @@ static void drm_ati_free_pcigart_table(void *address, int order) struct page *page; int i; int num_pages = 1 << order; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); page = virt_to_page((unsigned long)address); diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 314c2329..866878aa 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -106,7 +106,7 @@ int drm_irq_install(struct drm_device * dev) dev->irq_enabled = 1; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq); + DRM_DEBUG("irq=%d\n", dev->irq); if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { init_waitqueue_head(&dev->vbl_queue); @@ -164,7 +164,7 @@ int drm_irq_uninstall(struct drm_device * dev) if (!irq_enabled) return -EINVAL; - DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq); + DRM_DEBUG("irq=%d\n", dev->irq); dev->driver->irq_uninstall(dev); diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c index 920b11c8..77b9f95d 100644 --- a/linux-core/drm_scatter.c +++ b/linux-core/drm_scatter.c @@ -68,7 +68,7 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) struct drm_sg_mem *entry; unsigned long pages, i, j; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); if (!drm_core_check_feature(dev, DRIVER_SG)) return -EINVAL; @@ -82,7 +82,7 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) memset(entry, 0, sizeof(*entry)); pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; - DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages); + DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages); entry->pages = pages; entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist), @@ -123,8 +123,8 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) entry->handle = ScatterHandle((unsigned long)entry->virtual); - DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle); - DRM_DEBUG("sg alloc virtual = %p\n", entry->virtual); + DRM_DEBUG("handle = %08lx\n", entry->handle); + DRM_DEBUG("virtual = %p\n", entry->virtual); for (i = (unsigned long)entry->virtual, j = 0; j < pages; i += PAGE_SIZE, j++) { @@ -211,7 +211,7 @@ int drm_sg_free(struct drm_device *dev, void *data, if (!entry || entry->handle != request->handle) return -EINVAL; - DRM_DEBUG("sg free virtual = %p\n", entry->virtual); + DRM_DEBUG("virtual = %p\n", entry->virtual); drm_sg_cleanup(entry); diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index dcefcb34..c481a530 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -189,7 +189,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, return NOPAGE_SIGBUS; get_page(page); - DRM_DEBUG("shm_nopage 0x%lx\n", address); + DRM_DEBUG("0x%lx\n", address); return page; } @@ -305,7 +305,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma, get_page(page); - DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr); + DRM_DEBUG("0x%lx (page %lu)\n", address, page_nr); return page; } diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index c085fbc9..3c9ca3b2 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -589,7 +589,7 @@ static void i810EmitState(struct drm_device * dev) drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; - DRM_DEBUG("%s %x\n", __FUNCTION__, dirty); + DRM_DEBUG("%x\n", dirty); if (dirty & I810_UPLOAD_BUFFERS) { i810EmitDestVerified(dev, sarea_priv->BufferState); @@ -821,8 +821,7 @@ static void i810_dma_dispatch_flip(struct drm_device * dev) int pitch = dev_priv->pitch; RING_LOCALS; - DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", - __FUNCTION__, + DRM_DEBUG("page=%d pfCurrentPage=%d\n", dev_priv->current_page, dev_priv->sarea_priv->pf_current_page); @@ -867,8 +866,6 @@ static void i810_dma_quiescent(struct drm_device * dev) drm_i810_private_t *dev_priv = dev->dev_private; RING_LOCALS; -/* printk("%s\n", __FUNCTION__); */ - i810_kernel_lost_context(dev); BEGIN_LP_RING(4); @@ -888,8 +885,6 @@ static int i810_flush_queue(struct drm_device * dev) int i, ret = 0; RING_LOCALS; -/* printk("%s\n", __FUNCTION__); */ - i810_kernel_lost_context(dev); BEGIN_LP_RING(2); @@ -968,7 +963,7 @@ static int i810_dma_vertex(struct drm_device *dev, void *data, LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", + DRM_DEBUG("idx %d used %d discard %d\n", vertex->idx, vertex->used, vertex->discard); if (vertex->idx < 0 || vertex->idx > dma->buf_count) @@ -1006,7 +1001,7 @@ static int i810_clear_bufs(struct drm_device *dev, void *data, static int i810_swap_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEBUG("i810_swap_bufs\n"); + DRM_DEBUG("\n"); LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -1087,11 +1082,10 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf, sarea_priv->dirty = 0x7f; - DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n", address, used); + DRM_DEBUG("addr 0x%lx, used 0x%x\n", address, used); dev_priv->counter++; DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter); - DRM_DEBUG("i810_dma_dispatch_mc\n"); DRM_DEBUG("start : %lx\n", start); DRM_DEBUG("used : %d\n", used); DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4); @@ -1197,7 +1191,7 @@ static void i810_do_init_pageflip(struct drm_device * dev) { drm_i810_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); dev_priv->page_flipping = 1; dev_priv->current_page = 0; dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; @@ -1207,7 +1201,7 @@ static int i810_do_cleanup_pageflip(struct drm_device * dev) { drm_i810_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); if (dev_priv->current_page != 0) i810_dma_dispatch_flip(dev); @@ -1220,7 +1214,7 @@ static int i810_flip_bufs(struct drm_device *dev, void *data, { drm_i810_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); LOCK_TEST_WITH_RETURN(dev, file_priv); diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index 86278e3d..f5c175fe 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -145,7 +145,7 @@ extern int i810_max_ioctl; #define BEGIN_LP_RING(n) do { \ if (I810_VERBOSE) \ - DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__);\ + DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \ if (dev_priv->ring.space < n*4) \ i810_wait_ring(dev, n*4); \ dev_priv->ring.space -= n*4; \ diff --git a/linux-core/sis_mm.c b/linux-core/sis_mm.c index 5110d6e5..6782731d 100644 --- a/linux-core/sis_mm.c +++ b/linux-core/sis_mm.c @@ -114,7 +114,7 @@ static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file dev_priv->vram_offset = fb->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size); + DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size); return 0; } @@ -204,7 +204,7 @@ static int sis_ioctl_agp_init(struct drm_device *dev, void *data, dev_priv->agp_offset = agp->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size); + DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size); return 0; } diff --git a/linux-core/via_mm.c b/linux-core/via_mm.c index 270eac15..3f75af38 100644 --- a/linux-core/via_mm.c +++ b/linux-core/via_mm.c @@ -53,7 +53,7 @@ int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) dev_priv->agp_offset = agp->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size); + DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size); return 0; } @@ -77,7 +77,7 @@ int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) dev_priv->vram_offset = fb->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size); + DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size); return 0; -- cgit v1.2.3 From f5e5e5c0ea7d7a69f7bf16c718bf757fbb4b541d Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 4 Jan 2008 23:47:57 +0200 Subject: drm: One forgotten rename of 'mask' to 'proposed_flags'. Due to commit d1187641d64f442968a3b9ea6a19de6cdd45acd4. --- linux-core/drm_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 67c8c998..a745a7d9 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -232,7 +232,7 @@ static struct page *drm_bo_vm_fault(struct vm_area_struct *vma, if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) { unsigned long _end = jiffies + 3*DRM_HZ; - uint32_t new_mask = bo->mem.mask | + uint32_t new_mask = bo->mem.proposed_flags | DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_FORCE_MAPPABLE; -- cgit v1.2.3 From fa5e18679fcdb7bd2d69c605183b0b205416bf2b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 7 Jan 2008 16:55:20 +1100 Subject: nv50: use dummy page in gart tables Just to be safe, we don't really know exactly how the tables work yet, so we can't be certain there's a way to say "page not present". --- linux-core/nouveau_sgdma.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'linux-core') diff --git a/linux-core/nouveau_sgdma.c b/linux-core/nouveau_sgdma.c index 6c61819f..cc4d5a92 100644 --- a/linux-core/nouveau_sgdma.c +++ b/linux-core/nouveau_sgdma.c @@ -139,8 +139,8 @@ nouveau_sgdma_unbind(struct drm_ttm_backend *be) if (dev_priv->card_type < NV_50) { INSTANCE_WR(gpuobj, pte, pteval | 3); } else { - INSTANCE_WR(gpuobj, (pte<<1)+0, 0x00000010); - INSTANCE_WR(gpuobj, (pte<<1)+1, 0x00000004); + INSTANCE_WR(gpuobj, (pte<<1)+0, pteval | 0x21); + INSTANCE_WR(gpuobj, (pte<<1)+1, 0x00000000); } pte++; @@ -221,15 +221,14 @@ nouveau_sgdma_init(struct drm_device *dev) return ret; } - if (dev_priv->card_type < NV_50) { - dev_priv->gart_info.sg_dummy_page = - alloc_page(GFP_KERNEL|__GFP_DMA32); - SetPageLocked(dev_priv->gart_info.sg_dummy_page); - dev_priv->gart_info.sg_dummy_bus = - pci_map_page(dev->pdev, - dev_priv->gart_info.sg_dummy_page, 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + dev_priv->gart_info.sg_dummy_page = + alloc_page(GFP_KERNEL|__GFP_DMA32); + SetPageLocked(dev_priv->gart_info.sg_dummy_page); + dev_priv->gart_info.sg_dummy_bus = + pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (dev_priv->card_type < NV_50) { /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE * on those cards? */ @@ -245,8 +244,9 @@ nouveau_sgdma_init(struct drm_device *dev) } } else { for (i=0; igart_info.sg_dummy_bus | 0x21); + INSTANCE_WR(gpuobj, (i+4)/4, 0); } } -- cgit v1.2.3 From 62df4f0a48776e55443d7f61a41e1ed0fb77b6ed Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 14 Jan 2008 19:36:10 +1000 Subject: fixup i915 compat resource allocation --- linux-core/i915_compat.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'linux-core') diff --git a/linux-core/i915_compat.c b/linux-core/i915_compat.c index 58fb8418..f77260b1 100644 --- a/linux-core/i915_compat.c +++ b/linux-core/i915_compat.c @@ -21,6 +21,7 @@ static struct _i9xx_private_compat { void __iomem *flush_page; + int resource_valid; struct resource ifp_resource; } i9xx_private; @@ -57,16 +58,17 @@ static void intel_i915_setup_chipset_flush(struct pci_dev *pdev) pci_read_config_dword(pdev, I915_IFPADDR, &temp); if (!(temp & 0x1)) { intel_alloc_chipset_flush_resource(pdev); - + i9xx_private.resource_valid = 1; pci_write_config_dword(pdev, I915_IFPADDR, (i9xx_private.ifp_resource.start & 0xffffffff) | 0x1); } else { temp &= ~1; + i9xx_private.resource_valid = 1; i9xx_private.ifp_resource.start = temp; i9xx_private.ifp_resource.end = temp + PAGE_SIZE; ret = request_resource(&iomem_resource, &i9xx_private.ifp_resource); if (ret) { - i9xx_private.ifp_resource.start = 0; + i9xx_private.resource_valid = 0; printk("Failed inserting resource into tree\n"); } } @@ -84,6 +86,7 @@ static void intel_i965_g33_setup_chipset_flush(struct pci_dev *pdev) intel_alloc_chipset_flush_resource(pdev); + i9xx_private.resource_valid = 1; pci_write_config_dword(pdev, I965_IFPADDR + 4, upper_32_bits(i9xx_private.ifp_resource.start)); pci_write_config_dword(pdev, I965_IFPADDR, (i9xx_private.ifp_resource.start & 0xffffffff) | 0x1); @@ -93,11 +96,12 @@ static void intel_i965_g33_setup_chipset_flush(struct pci_dev *pdev) temp_lo &= ~0x1; l64 = ((u64)temp_hi << 32) | temp_lo; + i9xx_private.resource_valid = 1; i9xx_private.ifp_resource.start = l64; i9xx_private.ifp_resource.end = l64 + PAGE_SIZE; ret = request_resource(&iomem_resource, &i9xx_private.ifp_resource); if (!ret) { - i9xx_private.ifp_resource.start = 0; + i9xx_private.resource_valid = 0; printk("Failed inserting resource into tree\n"); } } @@ -167,7 +171,9 @@ static void intel_i9xx_setup_flush(struct drm_device *dev) static void intel_i9xx_fini_flush(struct drm_device *dev) { iounmap(i9xx_private.flush_page); - release_resource(&i9xx_private.ifp_resource); + if (i9xx_private.resource_valid) + release_resource(&i9xx_private.ifp_resource); + i9xx_private.resource_valid = 0; } static void intel_i9xx_flush_page(struct drm_device *dev) -- cgit v1.2.3 From 806c1929dcd344f6eab3133584a9c4ce9f3f47bc Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Tue, 15 Jan 2008 09:19:02 +0800 Subject: this is to fix a deadloop in drm hang system issue. (1 << bits) is an undefined value when bits == 32. gcc may generate 1 with this expression which will lead to an infinite retry loop in drm_ht_just_insert_please. Because of the different implement of hash_long, this issue is more frequenly see on 64 bit system --- linux-core/drm_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index 5ade6178..7d2e3a2b 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -44,7 +44,7 @@ int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item, item->owner = priv; ret = drm_ht_just_insert_please(&dev->object_hash, &item->hash, - (unsigned long)item, 32, 0, 0); + (unsigned long)item, 31, 0, 0); if (ret) return ret; -- cgit v1.2.3 From 099e89edf094ec231621b67129e9226ba50e99ad Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 15 Jan 2008 09:46:59 +0100 Subject: Define i915_compat.c upper_32_bits for kernels < 2.6.21 --- linux-core/i915_compat.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'linux-core') diff --git a/linux-core/i915_compat.c b/linux-core/i915_compat.c index f77260b1..cc024085 100644 --- a/linux-core/i915_compat.c +++ b/linux-core/i915_compat.c @@ -19,6 +19,10 @@ #define I915_IFPADDR 0x60 #define I965_IFPADDR 0x70 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) +#define upper_32_bits(_val) (((u64)(_val)) >> 32) +#endif + static struct _i9xx_private_compat { void __iomem *flush_page; int resource_valid; -- cgit v1.2.3 From ac6b3780c816f81c8159ff5ba07a77563e26a1c5 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Wed, 9 Jan 2008 11:30:35 +0800 Subject: i915: Add chipset id for Intel Integrated Graphics Device This adds new chipset id in drm. Signed-off-by: Zhenyu Wang --- linux-core/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index d3a4ab35..a8ce0f5e 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -330,7 +330,7 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); dev_priv->saveDSPBBASE = I915_READ(DSPBBASE); - if (IS_I965GM(dev)) { + if (IS_I965GM(dev) || IS_IGD_GM(dev)) { dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } -- cgit v1.2.3 From c6f175cbea1dba3fc26426243acc55b89b8a8064 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 17 Jan 2008 18:51:56 -0500 Subject: i915: fix invalid opcode exception on cpus without clflush i915_flush_ttm was unconditionally executing a clflush instruction to (obviously) flush the cache. Instead, check if the cpu supports clflush, and if not, fall back to calling wbinvd to flush the entire cache. Signed-off-by: Kyle McMartin --- linux-core/i915_buffer.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'linux-core') diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 3dd236dd..08067476 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -286,7 +286,18 @@ void i915_flush_ttm(struct drm_ttm *ttm) return; DRM_MEMORYBARRIER(); + +#ifdef CONFIG_X86_32 + /* Hopefully nobody has built an x86-64 processor without clflush */ + if (!cpu_has_clflush) { + wbinvd(); + DRM_MEMORYBARRIER(); + return; + } +#endif + for (i = ttm->num_pages - 1; i >= 0; i--) drm_cache_flush_page(drm_ttm_get_page(ttm, i)); + DRM_MEMORYBARRIER(); } -- cgit v1.2.3 From c57f43e3a266d247c8a2be6fd7702caab2dc009b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 23 Jan 2008 16:45:09 +1000 Subject: i915/flush: get the ret the right way around --- linux-core/i915_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/i915_compat.c b/linux-core/i915_compat.c index cc024085..f3e0a081 100644 --- a/linux-core/i915_compat.c +++ b/linux-core/i915_compat.c @@ -104,7 +104,7 @@ static void intel_i965_g33_setup_chipset_flush(struct pci_dev *pdev) i9xx_private.ifp_resource.start = l64; i9xx_private.ifp_resource.end = l64 + PAGE_SIZE; ret = request_resource(&iomem_resource, &i9xx_private.ifp_resource); - if (!ret) { + if (ret) { i9xx_private.resource_valid = 0; printk("Failed inserting resource into tree\n"); } -- cgit v1.2.3 From bfdddd218ec3e7ce3f8e765b93af35661a7bf0fd Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 24 Jan 2008 20:59:51 -0800 Subject: Fixup modeset ioctl number & typedef usage Should be 0x08 rather than 0xa0, and shouldn't use typedefs. --- linux-core/drm_irq.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 2a5a4539..367d2dd8 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -397,23 +397,17 @@ EXPORT_SYMBOL(drm_vblank_put); int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_modeset_ctl_t __user *argp = (void __user *)data; - drm_modeset_ctl_t modeset; + struct drm_modeset_ctl *modeset = data; int crtc, ret = 0; u32 new; - if (copy_from_user(&modeset, argp, sizeof(modeset))) { - ret = -EFAULT; - goto out; - } - - crtc = modeset.arg; + crtc = modeset->arg; if (crtc >= dev->num_crtcs) { ret = -EINVAL; goto out; } - switch (modeset.cmd) { + switch (modeset->cmd) { case _DRM_PRE_MODESET: dev->vblank_premodeset[crtc] = dev->driver->get_vblank_counter(dev, crtc); -- cgit v1.2.3