From 2186f9f6eff4b3b4f605d35a030c0910646865ab Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 12:49:20 -0400 Subject: [FreeBSD] Call drm_vblank_cleanup during irq uninstall I needed to re-arrange some functions for this. Also needed to call DRM_SPINUNINIT on the vbl_lock during cleanup. --- bsd-core/drm_irq.c | 287 +++++++++++++++++++++++++++-------------------------- 1 file changed, 145 insertions(+), 142 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 592e2ea8..4b10ba4f 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -66,6 +66,116 @@ drm_irq_handler_wrap(DRM_IRQ_ARGS) } #endif +static void vblank_disable_fn(void *arg) +{ + struct drm_device *dev = (struct drm_device *)arg; + unsigned long irqflags; + int i; + + for (i = 0; i < dev->num_crtcs; i++) { + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + if (atomic_read(&dev->vblank_refcount[i]) == 0 && + dev->vblank_enabled[i]) { + dev->driver.disable_vblank(dev, i); + dev->vblank_enabled[i] = 0; + } + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + } +} + +static void drm_vblank_cleanup(struct drm_device *dev) +{ + /* Bail if the driver didn't call drm_vblank_init() */ + if (dev->num_crtcs == 0) + return; + + callout_drain(&dev->vblank_disable_timer); + + vblank_disable_fn((void *)dev); + DRM_SPINUNINIT(&dev->vbl_lock); + + drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, + DRM_MEM_DRIVER); + + dev->num_crtcs = 0; +} + +int drm_vblank_init(struct drm_device *dev, int num_crtcs) +{ + int i, ret = -ENOMEM; + + callout_init(&dev->vblank_disable_timer, 0); + DRM_SPININIT(&dev->vbl_lock, "drm_vblk"); + 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 drm_vbl_sig) * 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_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vblank_refcount) + goto err; + + dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_enabled) + goto err; + + dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); + if (!dev->last_vblank) + goto err; + + dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), + DRM_MEM_DRIVER); + if (!dev->vblank_premodeset) + goto err; + + dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); + if (!dev->vblank_offset) + goto err; + + /* Zero per-crtc vblank stuff */ + for (i = 0; i < num_crtcs; i++) { + DRM_INIT_WAITQUEUE(&dev->vbl_queue[i]); + TAILQ_INIT(&dev->vbl_sigs[i]); + atomic_set(&dev->_vblank_count[i], 0); + atomic_set(&dev->vblank_refcount[i], 0); + } + + return 0; + +err: + drm_vblank_cleanup(dev); + return ret; +} + int drm_irq_install(struct drm_device *dev) { int retcode; @@ -175,6 +285,8 @@ int drm_irq_uninstall(struct drm_device *dev) #elif defined(__NetBSD__) || defined(__OpenBSD__) pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh); #endif + drm_vblank_cleanup(dev); + DRM_SPINUNINIT(&dev->irq_lock); return 0; @@ -208,27 +320,37 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) } } -static void vblank_disable_fn(void *arg) +u32 drm_vblank_count(struct drm_device *dev, int crtc) +{ + return atomic_read(&dev->_vblank_count[crtc]) + + dev->vblank_offset[crtc]; +} + +void drm_update_vblank_count(struct drm_device *dev, int crtc) { - struct drm_device *dev = (struct drm_device *)arg; unsigned long irqflags; - int i; + u32 cur_vblank, diff; - for (i = 0; i < dev->num_crtcs; i++) { - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - if (atomic_read(&dev->vblank_refcount[i]) == 0 && - dev->vblank_enabled[i]) { - dev->driver.disable_vblank(dev, i); - dev->vblank_enabled[i] = 0; - } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + /* + * 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); + DRM_SPINLOCK_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 - dev->last_vblank[crtc]; } -} + dev->last_vblank[crtc] = cur_vblank; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); -u32 drm_vblank_count(struct drm_device *dev, int crtc) -{ - return atomic_read(&dev->_vblank_count[crtc]) + - dev->vblank_offset[crtc]; + atomic_add(diff, &dev->_vblank_count[crtc]); } int drm_vblank_get(struct drm_device *dev, int crtc) @@ -261,40 +383,6 @@ void drm_vblank_put(struct drm_device *dev, int crtc) (timeout_t *)vblank_disable_fn, (void *)dev); } -void drm_handle_vblank(struct drm_device *dev, int crtc) -{ - drm_update_vblank_count(dev, crtc); - DRM_WAKEUP(&dev->vbl_queue[crtc]); - drm_vbl_send_signals(dev, crtc); -} - -void drm_update_vblank_count(struct drm_device *dev, int crtc) -{ - unsigned long irqflags; - u32 cur_vblank, diff; - - /* - * 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); - DRM_SPINLOCK_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 - dev->last_vblank[crtc]; - } - dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); - - atomic_add(diff, &dev->_vblank_count[crtc]); -} - int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -410,98 +498,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr return ret; } -static void drm_vblank_cleanup(struct drm_device *dev) -{ - /* Bail if the driver didn't call drm_vblank_init() */ - if (dev->num_crtcs == 0) - return; - - callout_stop(&dev->vblank_disable_timer); - - vblank_disable_fn((void *)dev); - - drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, - DRM_MEM_DRIVER); - - dev->num_crtcs = 0; -} - -int drm_vblank_init(struct drm_device *dev, int num_crtcs) -{ - int i, ret = -ENOMEM; - - callout_init(&dev->vblank_disable_timer, 0); - DRM_SPININIT(&dev->vbl_lock, "drm_vblk"); - 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 drm_vbl_sig) * 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_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vblank_refcount) - goto err; - - dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); - if (!dev->vblank_enabled) - goto err; - - dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->last_vblank) - goto err; - - dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), - DRM_MEM_DRIVER); - if (!dev->vblank_premodeset) - goto err; - - dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->vblank_offset) - goto err; - - /* Zero per-crtc vblank stuff */ - for (i = 0; i < num_crtcs; i++) { - DRM_INIT_WAITQUEUE(&dev->vbl_queue[i]); - TAILQ_INIT(&dev->vbl_sigs[i]); - atomic_set(&dev->_vblank_count[i], 0); - atomic_set(&dev->vblank_refcount[i], 0); - } - - return 0; - -err: - drm_vblank_cleanup(dev); - return ret; -} - void drm_vbl_send_signals(struct drm_device *dev, int crtc) { } @@ -530,6 +526,13 @@ void drm_vbl_send_signals(struct drm_device *dev, int crtc ) } #endif +void drm_handle_vblank(struct drm_device *dev, int crtc) +{ + drm_update_vblank_count(dev, crtc); + DRM_WAKEUP(&dev->vbl_queue[crtc]); + drm_vbl_send_signals(dev, crtc); +} + static void drm_locked_task(void *context, int pending __unused) { struct drm_device *dev = context; -- cgit v1.2.3 From ac4da869285173ad0ac947bdf41ffe10efe21c05 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 12:56:34 -0400 Subject: [FreeBSD] Add symlink for radeon_microcode.h --- bsd-core/radeon_microcode.h | 1 + 1 file changed, 1 insertion(+) create mode 120000 bsd-core/radeon_microcode.h (limited to 'bsd-core') diff --git a/bsd-core/radeon_microcode.h b/bsd-core/radeon_microcode.h new file mode 120000 index 00000000..709fff30 --- /dev/null +++ b/bsd-core/radeon_microcode.h @@ -0,0 +1 @@ +../shared-core/radeon_microcode.h \ No newline at end of file -- cgit v1.2.3 From 4ce47fd328cd885d66abdd42db1f7c054bd44498 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 16:17:31 -0400 Subject: [FreeBSD] Get rid of vbl_lock and re-use irq_lock. --- bsd-core/drmP.h | 5 +---- bsd-core/drm_irq.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 4c35cdb2..21cf623a 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -788,11 +788,10 @@ 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) */ - struct mtx vbl_lock; struct drm_vbl_sig_list *vbl_sigs; /* signal list to send on VBLANK */ 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 */ + u32 *last_vblank; /* protected by dev->irq_lock, used */ /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ @@ -802,8 +801,6 @@ struct drm_device { struct callout vblank_disable_timer; unsigned long max_vblank_count; /* size of vblank counter register */ int num_crtcs; - atomic_t vbl_received; - atomic_t vbl_received2; #ifdef __FreeBSD__ struct sigio *buf_sigio; /* Processes waiting for SIGIO */ diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 4b10ba4f..57a70263 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -73,13 +73,13 @@ static void vblank_disable_fn(void *arg) int i; for (i = 0; i < dev->num_crtcs; i++) { - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } } @@ -92,7 +92,6 @@ static void drm_vblank_cleanup(struct drm_device *dev) callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); - DRM_SPINUNINIT(&dev->vbl_lock); drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, DRM_MEM_DRIVER); @@ -119,7 +118,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) int i, ret = -ENOMEM; callout_init(&dev->vblank_disable_timer, 0); - DRM_SPININIT(&dev->vbl_lock, "drm_vblk"); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -339,7 +337,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { diff = dev->max_vblank_count - dev->last_vblank[crtc]; @@ -348,7 +346,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -358,7 +356,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) unsigned long irqflags; int ret = 0; - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ atomic_add_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 1 && @@ -369,7 +367,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) else dev->vblank_enabled[crtc] = 1; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); return ret; } -- cgit v1.2.3 From 416754f1cc5a55b1c6b2d2fa2f501b18462d62e6 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 19:34:29 -0400 Subject: [FreeBSD] Declare vblank_disable_fn callout MPSAFE. --- bsd-core/drm_irq.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 57a70263..b76e96dd 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -72,23 +72,40 @@ static void vblank_disable_fn(void *arg) unsigned long irqflags; int i; + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + if (callout_pending(&dev->vblank_disable_timer)) { + /* callout was reset */ + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + return; + } + if (!callout_active(&dev->vblank_disable_timer)) { + /* callout was stopped */ + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + return; + } + callout_deactivate(&dev->vblank_disable_timer); + for (i = 0; i < dev->num_crtcs; i++) { - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } static void drm_vblank_cleanup(struct drm_device *dev) { + unsigned long irqflags; + /* Bail if the driver didn't call drm_vblank_init() */ if (dev->num_crtcs == 0) return; + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + callout_stop(&dev->vblank_disable_timer); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); @@ -117,7 +134,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) { int i, ret = -ENOMEM; - callout_init(&dev->vblank_disable_timer, 0); + callout_init_mtx(&dev->vblank_disable_timer, &dev->irq_lock, 1); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -374,11 +391,15 @@ int drm_vblank_get(struct drm_device *dev, int crtc) void drm_vblank_put(struct drm_device *dev, int crtc) { + unsigned long irqflags; + + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); /* Last user schedules interrupt disable */ atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 0) callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } int drm_modeset_ctl(struct drm_device *dev, void *data, -- cgit v1.2.3 From fc74c2e9d65dbd0c611e1610886df098c6e3273b Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 2 Jun 2008 13:12:59 -0400 Subject: [FreeBSD] Go back to using vbl_lock and move init/destroy to load/unload. --- bsd-core/drmP.h | 3 ++- bsd-core/drm_drv.c | 7 ++++++- bsd-core/drm_irq.c | 35 +++++++++++++++-------------------- 3 files changed, 23 insertions(+), 22 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 21cf623a..d3f53b86 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -733,6 +733,7 @@ struct drm_device { /* Locks */ #if defined(__FreeBSD__) && __FreeBSD_version > 500000 + struct mtx vbl_lock; /* protects vblank operations */ struct mtx dma_lock; /* protects dev->dma */ struct mtx irq_lock; /* protects irq condition checks */ struct mtx dev_lock; /* protects everything else */ @@ -791,7 +792,7 @@ struct drm_device { struct drm_vbl_sig_list *vbl_sigs; /* signal list to send on VBLANK */ 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->irq_lock, used */ + u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 9924ac34..ece00e18 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -202,7 +202,9 @@ int drm_attach(device_t nbdev, drm_pci_id_list_t *idlist) DRM_DEV_MODE, "dri/card%d", unit); #if __FreeBSD_version >= 500000 - mtx_init(&dev->dev_lock, "drm device", NULL, MTX_DEF); + mtx_init(&dev->dev_lock, "drmdev", NULL, MTX_DEF); + mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); + mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF); #endif @@ -594,6 +596,9 @@ error: #ifdef __FreeBSD__ destroy_dev(dev->devnode); #if __FreeBSD_version >= 500000 + mtx_destroy(&dev->drw_lock); + mtx_destroy(&dev->irq_lock); + mtx_destroy(&dev->vbl_lock); mtx_destroy(&dev->dev_lock); #endif #endif diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index b76e96dd..79f8f9ff 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -72,15 +72,15 @@ static void vblank_disable_fn(void *arg) unsigned long irqflags; int i; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (callout_pending(&dev->vblank_disable_timer)) { /* callout was reset */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } if (!callout_active(&dev->vblank_disable_timer)) { /* callout was stopped */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } callout_deactivate(&dev->vblank_disable_timer); @@ -92,7 +92,7 @@ static void vblank_disable_fn(void *arg) dev->vblank_enabled[i] = 0; } } - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } static void drm_vblank_cleanup(struct drm_device *dev) @@ -103,9 +103,9 @@ static void drm_vblank_cleanup(struct drm_device *dev) if (dev->num_crtcs == 0) return; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); callout_stop(&dev->vblank_disable_timer); - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); @@ -134,7 +134,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) { int i, ret = -ENOMEM; - callout_init_mtx(&dev->vblank_disable_timer, &dev->irq_lock, 1); + callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -212,8 +212,6 @@ int drm_irq_install(struct drm_device *dev) dev->context_flag = 0; - DRM_SPININIT(&dev->irq_lock, "DRM IRQ lock"); - /* Before installing handler */ dev->driver.irq_preinstall(dev); DRM_UNLOCK(); @@ -268,7 +266,6 @@ err: dev->irqrid = 0; } #endif - DRM_SPINUNINIT(&dev->irq_lock); DRM_UNLOCK(); return retcode; } @@ -302,8 +299,6 @@ int drm_irq_uninstall(struct drm_device *dev) #endif drm_vblank_cleanup(dev); - DRM_SPINUNINIT(&dev->irq_lock); - return 0; } @@ -354,7 +349,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { diff = dev->max_vblank_count - dev->last_vblank[crtc]; @@ -363,7 +358,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -373,7 +368,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) unsigned long irqflags; int ret = 0; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ atomic_add_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 1 && @@ -384,7 +379,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) else dev->vblank_enabled[crtc] = 1; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return ret; } @@ -393,13 +388,13 @@ void drm_vblank_put(struct drm_device *dev, int crtc) { unsigned long irqflags; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); /* Last user schedules interrupt disable */ atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 0) callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } int drm_modeset_ctl(struct drm_device *dev, void *data, @@ -488,9 +483,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr vblwait->reply.sequence = atomic_read(&dev->vbl_received); - DRM_SPINLOCK(&dev->irq_lock); + DRM_SPINLOCK(&dev->vbl_lock); TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link); - DRM_SPINUNLOCK(&dev->irq_lock); + DRM_SPINUNLOCK(&dev->vbl_lock); ret = 0; #endif ret = EINVAL; -- cgit v1.2.3 From 93c57ff4e5d9f62be0a353222fef564dd9e59e39 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 2 Jun 2008 19:35:00 -0400 Subject: [FreeBSD] Remove the locks in the vblank_disable_fn They are recursive and causing panics with witness enabled. --- bsd-core/drm_irq.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 79f8f9ff..132d01bb 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -69,18 +69,14 @@ drm_irq_handler_wrap(DRM_IRQ_ARGS) static void vblank_disable_fn(void *arg) { struct drm_device *dev = (struct drm_device *)arg; - unsigned long irqflags; int i; - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (callout_pending(&dev->vblank_disable_timer)) { /* callout was reset */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } if (!callout_active(&dev->vblank_disable_timer)) { /* callout was stopped */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } callout_deactivate(&dev->vblank_disable_timer); @@ -92,7 +88,6 @@ static void vblank_disable_fn(void *arg) dev->vblank_enabled[i] = 0; } } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } static void drm_vblank_cleanup(struct drm_device *dev) @@ -106,6 +101,7 @@ static void drm_vblank_cleanup(struct drm_device *dev) DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); callout_stop(&dev->vblank_disable_timer); DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); -- cgit v1.2.3 From ec3d9960219e49e1bd24a097e04c3da88e2fcc53 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 3 Jun 2008 13:02:38 -0400 Subject: [FreeBSD] Forgot to call mtx_destroy on all the locks at unload. --- bsd-core/drm_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'bsd-core') diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index ece00e18..1616dbb4 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -655,6 +655,9 @@ static void drm_unload(struct drm_device *dev) drm_mem_uninit(); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 + mtx_destroy(&dev->drw_lock); + mtx_destroy(&dev->irq_lock); + mtx_destroy(&dev->vbl_lock); mtx_destroy(&dev->dev_lock); #endif } -- cgit v1.2.3 From 6d6921719c7d475856199ddbe88bbe11fc882ba6 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 3 Jun 2008 16:21:13 -0400 Subject: [FreeBSD] Incorporate vblank fixes for bsd. --- bsd-core/drmP.h | 7 ++-- bsd-core/drm_irq.c | 93 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 65 insertions(+), 35 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index d3f53b86..88ea4e69 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -794,13 +794,12 @@ struct drm_device { 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 */ int *vblank_enabled; /* so we don't call enable more than */ /* once per disable */ - u32 *vblank_premodeset; /* were lost during modeset */ + u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ + int *vblank_suspend; /* Don't wait while crtc is likely disabled */ struct callout vblank_disable_timer; - unsigned long max_vblank_count; /* size of vblank counter register */ + u32 max_vblank_count; /* size of vblank counter register */ int num_crtcs; #ifdef __FreeBSD__ diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 132d01bb..c3ecd28b 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -120,15 +120,15 @@ static void drm_vblank_cleanup(struct drm_device *dev) DRM_MEM_DRIVER); drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, - DRM_MEM_DRIVER); + drm_free(dev->vblank_suspend, sizeof(*dev->vblank_suspend) * + dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs = 0; } int drm_vblank_init(struct drm_device *dev, int num_crtcs) { - int i, ret = -ENOMEM; + int i, ret = ENOMEM; callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); atomic_set(&dev->vbl_signal_pending, 0); @@ -168,8 +168,9 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_premodeset) goto err; - dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->vblank_offset) + dev->vblank_suspend = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_suspend) goto err; /* Zero per-crtc vblank stuff */ @@ -328,8 +329,7 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) u32 drm_vblank_count(struct drm_device *dev, int crtc) { - return atomic_read(&dev->_vblank_count[crtc]) + - dev->vblank_offset[crtc]; + return atomic_read(&dev->_vblank_count[crtc]); } void drm_update_vblank_count(struct drm_device *dev, int crtc) @@ -337,6 +337,9 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) unsigned long irqflags; u32 cur_vblank, diff; + if (dev->vblank_suspend[crtc]) + return; + /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -347,9 +350,16 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) cur_vblank = dev->driver.get_vblank_counter(dev, crtc); DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; + if (cur_vblank == dev->last_vblank[crtc] - 1) { + diff = 0; + } else { + diff = dev->max_vblank_count - + dev->last_vblank[crtc]; + diff += cur_vblank; + } + + DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", + crtc, dev->last_vblank[crtc], cur_vblank, diff); } else { diff = cur_vblank - dev->last_vblank[crtc]; } @@ -398,11 +408,10 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, { struct drm_modeset_ctl *modeset = data; int crtc, ret = 0; - u32 new; crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { - ret = -EINVAL; + ret = EINVAL; goto out; } @@ -410,13 +419,28 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, case _DRM_PRE_MODESET: dev->vblank_premodeset[crtc] = dev->driver.get_vblank_counter(dev, crtc); + dev->vblank_suspend[crtc] = 1; break; case _DRM_POST_MODESET: - new = dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; + if (dev->vblank_suspend[crtc]) { + u32 new = dev->driver.get_vblank_counter(dev, crtc); + + /* Compensate for spurious wraparound */ + if (new < dev->vblank_premodeset[crtc]) { + atomic_sub(dev->max_vblank_count + new - + dev->vblank_premodeset[crtc], + &dev->_vblank_count[crtc]); + DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" + " => _vblank_count[%d]-=0x%x\n", crtc, + dev->vblank_premodeset[crtc], new, + crtc, dev->max_vblank_count + new - + dev->vblank_premodeset[crtc]); + } + } + dev->vblank_suspend[crtc] = 0; break; default: - ret = -EINVAL; + ret = EINVAL; break; } @@ -427,7 +451,6 @@ out: int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_wait_vblank_t *vblwait = data; - struct timeval now; int ret = 0; int flags, seq, crtc; @@ -473,6 +496,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (vbl_sig == NULL) return ENOMEM; + if (dev->vblank_suspend[crtc]) + return EBUSY; + vbl_sig->sequence = vblwait->request.sequence; vbl_sig->signo = vblwait->request.signal; vbl_sig->pid = DRM_CURRENTPID; @@ -486,23 +512,28 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr #endif ret = EINVAL; } else { - unsigned long cur_vblank; - - DRM_LOCK(); - /* shared code returns -errno */ - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - (((cur_vblank = drm_vblank_count(dev, crtc)) + if (!dev->vblank_suspend[crtc]) { + DRM_LOCK(); + /* shared code returns -errno */ + + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + ((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); - DRM_UNLOCK(); + drm_vblank_put(dev, crtc); + DRM_UNLOCK(); + } - microtime(&now); - vblwait->reply.tval_sec = now.tv_sec; - vblwait->reply.tval_usec = now.tv_usec; + if (ret != EINTR) { + struct timeval now; + + microtime(&now); + vblwait->reply.tval_sec = now.tv_sec; + vblwait->reply.tval_usec = now.tv_usec; + vblwait->reply.sequence = drm_vblank_count(dev, crtc); + } } return ret; -- cgit v1.2.3 From 96141bd33c0d6c4b95a2adb668538ffc1103cc18 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Thu, 5 Jun 2008 12:46:39 -0400 Subject: [FreeBSD] We need to request busmastering support. This seems to be the key to getting at least some radeon cards working. Most, if not all drivers need it enabled, so just request it once the driver has attached. --- bsd-core/drm_drv.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'bsd-core') diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 1616dbb4..740a8b57 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -544,6 +544,8 @@ static int drm_load(struct drm_device *dev) /* Shared code returns -errno. */ retcode = -dev->driver.load(dev, dev->id_entry->driver_private); + if (pci_enable_busmaster(dev->device)) + DRM_ERROR("Request to enable bus-master failed.\n"); DRM_UNLOCK(); if (retcode != 0) goto error; @@ -654,6 +656,10 @@ static void drm_unload(struct drm_device *dev) delete_unrhdr(dev->drw_unrhdr); drm_mem_uninit(); + + if (pci_disable_busmaster(dev->device)) + DRM_ERROR("Request to disable bus-master failed.\n"); + #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 mtx_destroy(&dev->drw_lock); mtx_destroy(&dev->irq_lock); -- cgit v1.2.3 From 3b6ca4bf3f334341a158a9917ef117c23f145597 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Wed, 4 Jun 2008 15:04:41 -0400 Subject: [FreeBSD] Rework ati_pcigart.c This is mostly just a diff reduction with the linux version. I'm not convinced that it will make anything better. --- bsd-core/ati_pcigart.c | 127 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 39 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/ati_pcigart.c b/bsd-core/ati_pcigart.c index 2b511ada..f8d3f18d 100644 --- a/bsd-core/ati_pcigart.c +++ b/bsd-core/ati_pcigart.c @@ -34,76 +34,125 @@ #include "drmP.h" #define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */ +#define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) + +#define ATI_PCIE_WRITE 0x4 +#define ATI_PCIE_READ 0x8 + +static int drm_ati_alloc_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, + PAGE_SIZE, + gart_info->table_mask); + if (dev->sg->dmah == NULL) + return ENOMEM; + + return 0; +} + +static void drm_ati_free_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + drm_pci_free(dev, dev->sg->dmah); + dev->sg->dmah = NULL; +} + +int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) +{ + /* we need to support large memory configurations */ + if (dev->sg == NULL) { + DRM_ERROR("no scatter/gather memory!\n"); + return 0; + } + + if (gart_info->bus_addr) { + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { + gart_info->bus_addr = 0; + if (dev->sg->dmah) + drm_ati_free_pcigart_table(dev, gart_info); + } + } + + return 1; +} int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { + + void *address = NULL; unsigned long pages; - u32 *pci_gart = NULL, page_base; - int i, j; + u32 *pci_gart, page_base; + dma_addr_t bus_address = 0; + int i, j, ret = 0; + int max_pages; + dma_addr_t entry_addr; + /* we need to support large memory configurations */ if (dev->sg == NULL) { - DRM_ERROR( "no scatter/gather memory!\n" ); - return 0; + DRM_ERROR("no scatter/gather memory!\n"); + goto done; } if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { - /* GART table in system memory */ - dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, 0, - 0xfffffffful); - if (dev->sg->dmah == NULL) { - DRM_ERROR("cannot allocate PCI GART table!\n"); - return 0; + DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); + + ret = drm_ati_alloc_pcigart_table(dev, gart_info); + if (ret) { + DRM_ERROR("cannot allocate PCI GART page!\n"); + goto done; } - - gart_info->addr = (void *)dev->sg->dmah->vaddr; - gart_info->bus_addr = dev->sg->dmah->busaddr; - pci_gart = (u32 *)dev->sg->dmah->vaddr; + + address = (void *)dev->sg->dmah->vaddr; + bus_address = dev->sg->dmah->busaddr; } else { - /* GART table in framebuffer memory */ - pci_gart = gart_info->addr; + address = gart_info->addr; + bus_address = gart_info->bus_addr; + DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", + (unsigned int)bus_address, (unsigned long)address); } - - pages = DRM_MIN(dev->sg->pages, gart_info->table_size / sizeof(u32)); - bzero(pci_gart, gart_info->table_size); + pci_gart = (u32 *) address; - KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (dev->sg->pages <= max_pages) + ? dev->sg->pages : max_pages; + + memset(pci_gart, 0, max_pages * sizeof(u32)); - for ( i = 0 ; i < pages ; i++ ) { - page_base = (u32) dev->sg->busaddr[i]; + KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); + for (i = 0; i < pages; i++) { + entry_addr = dev->sg->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { + page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK; switch(gart_info->gart_reg_if) { case DRM_ATI_GART_IGP: - *pci_gart = cpu_to_le32(page_base | 0xc); + page_base |= (upper_32_bits(entry_addr) & 0xff) << 4; + page_base |= 0xc; break; case DRM_ATI_GART_PCIE: - *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); + page_base >>= 8; + page_base |= (upper_32_bits(entry_addr) & 0xff) << 24; + page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; break; default: - *pci_gart = cpu_to_le32(page_base); + case DRM_ATI_GART_PCI: break; } + *pci_gart = cpu_to_le32(page_base); pci_gart++; - page_base += ATI_PCIGART_PAGE_SIZE; + entry_addr += ATI_PCIGART_PAGE_SIZE; } } DRM_MEMORYBARRIER(); - return 1; -} - -int drm_ati_pcigart_cleanup(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) -{ - if (dev->sg == NULL) { - DRM_ERROR( "no scatter/gather memory!\n" ); - return 0; - } - - drm_pci_free(dev, dev->sg->dmah); + ret = 1; - return 1; + done: + gart_info->addr = address; + gart_info->bus_addr = bus_address; + return ret; } -- cgit v1.2.3 From 116870a908edd8da02381d23694b321e8878f92e Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 3 Jun 2008 21:15:54 -0400 Subject: I915 suspend/resume for FreeBSD --- bsd-core/i915/Makefile | 2 +- bsd-core/i915_drv.c | 32 +++++++++++++++++++++++++++++++- bsd-core/i915_suspend.c | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) create mode 120000 bsd-core/i915_suspend.c (limited to 'bsd-core') diff --git a/bsd-core/i915/Makefile b/bsd-core/i915/Makefile index 6fd7d728..f88155a5 100644 --- a/bsd-core/i915/Makefile +++ b/bsd-core/i915/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/.. KMOD = i915 NO_MAN = YES -SRCS = i915_dma.c i915_drv.c i915_irq.c i915_mem.c +SRCS = i915_dma.c i915_drv.c i915_irq.c i915_mem.c i915_suspend.c SRCS += device_if.h bus_if.h pci_if.h opt_drm.h CFLAGS += ${DEBUG_FLAGS} -I. -I.. diff --git a/bsd-core/i915_drv.c b/bsd-core/i915_drv.c index e6769d17..c19ef5db 100644 --- a/bsd-core/i915_drv.c +++ b/bsd-core/i915_drv.c @@ -40,10 +40,38 @@ static drm_pci_id_list_t i915_pciidlist[] = { i915_PCI_IDS }; +static int i915_suspend(device_t nbdev) +{ + struct drm_device *dev = device_get_softc(nbdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!dev || !dev_priv) { + DRM_ERROR("dev: 0x%lx, dev_priv: 0x%lx\n", + (unsigned long) dev, (unsigned long) dev_priv); + DRM_ERROR("DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + i915_save_state(dev); + + return (bus_generic_suspend(nbdev)); +} + +static int i915_resume(device_t nbdev) +{ + struct drm_device *dev = device_get_softc(nbdev); + + i915_restore_state(dev); + + return (bus_generic_resume(nbdev)); +} + static void i915_configure(struct drm_device *dev) { - dev->driver.buf_priv_size = 1; /* No dev_priv */ + dev->driver.buf_priv_size = sizeof(drm_i915_private_t); dev->driver.load = i915_driver_load; + dev->driver.unload = i915_driver_unload; + dev->driver.firstopen = i915_driver_firstopen; dev->driver.preclose = i915_driver_preclose; dev->driver.lastclose = i915_driver_lastclose; dev->driver.device_is_agp = i915_driver_device_is_agp; @@ -94,6 +122,8 @@ static device_method_t i915_methods[] = { /* Device interface */ DEVMETHOD(device_probe, i915_probe), DEVMETHOD(device_attach, i915_attach), + DEVMETHOD(device_suspend, i915_suspend), + DEVMETHOD(device_resume, i915_resume), DEVMETHOD(device_detach, drm_detach), { 0, 0 } diff --git a/bsd-core/i915_suspend.c b/bsd-core/i915_suspend.c new file mode 120000 index 00000000..b55754c5 --- /dev/null +++ b/bsd-core/i915_suspend.c @@ -0,0 +1 @@ +../shared-core/i915_suspend.c \ No newline at end of file -- cgit v1.2.3 From 29ffa0017d002f9e74de42817b962b6ca2e5f20a Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Fri, 13 Jun 2008 17:41:20 -0400 Subject: [FreeBSD] Fix another lock leak Reported by vehemens --- bsd-core/drm_bufs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drm_bufs.c b/bsd-core/drm_bufs.c index 3508331a..c793634b 100644 --- a/bsd-core/drm_bufs.c +++ b/bsd-core/drm_bufs.c @@ -832,12 +832,12 @@ int drm_addbufs_sg(struct drm_device *dev, drm_buf_desc_t *request) if (request->count < 0 || request->count > 4096) return EINVAL; - DRM_SPINLOCK(&dev->dma_lock); - order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return EINVAL; + DRM_SPINLOCK(&dev->dma_lock); + /* No more allocations after first buffer-using ioctl. */ if (dev->buf_use != 0) { DRM_SPINUNLOCK(&dev->dma_lock); -- cgit v1.2.3 From 96580f660e5509dcf6c34de5630e3d36b156bcd5 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 9 Jun 2008 08:54:53 -0400 Subject: [FreeBSD] We aren't allowed to hold locks over bus_dma_tag_create or bus_dmamem_alloc. --- bsd-core/drm_pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'bsd-core') diff --git a/bsd-core/drm_pci.c b/bsd-core/drm_pci.c index 6b411abb..f23b2a5b 100644 --- a/bsd-core/drm_pci.c +++ b/bsd-core/drm_pci.c @@ -71,6 +71,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size, return NULL; #ifdef __FreeBSD__ + DRM_UNLOCK(); ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */ maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ NULL, NULL, /* filtfunc, filtfuncargs */ @@ -79,6 +80,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size, &dmah->tag); if (ret != 0) { free(dmah, M_DRM); + DRM_LOCK(); return NULL; } @@ -87,9 +89,10 @@ drm_pci_alloc(struct drm_device *dev, size_t size, if (ret != 0) { bus_dma_tag_destroy(dmah->tag); free(dmah, M_DRM); + DRM_LOCK(); return NULL; } - + DRM_LOCK(); ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size, drm_pci_busdma_callback, dmah, 0); if (ret != 0) { -- cgit v1.2.3 From 74cf1f91be7f4139601624af0343e3d411190dec Mon Sep 17 00:00:00 2001 From: Owain Gordon Ainsworth Date: Mon, 7 Jul 2008 17:23:48 +0100 Subject: BSD: change drm_locked_task*() to use the same scheme as linux. The current code can sleep in an interrupt handler, that is bad. So instead if we can't grab the lock, flag it and run the tasklet on unlock. Signed-off-by: Robert Noland --- bsd-core/drmP.h | 1 + bsd-core/drm_drv.c | 1 + bsd-core/drm_irq.c | 45 +++++++++++++++++++++++---------------------- bsd-core/drm_lock.c | 7 +++++++ 4 files changed, 32 insertions(+), 22 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 88ea4e69..65d7fae4 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -739,6 +739,7 @@ struct drm_device { struct mtx dev_lock; /* protects everything else */ #endif DRM_SPINTYPE drw_lock; + DRM_SPINTYPE tsk_lock; /* Usage Counters */ int open_count; /* Outstanding files open */ diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 740a8b57..9bd6079f 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -206,6 +206,7 @@ int drm_attach(device_t nbdev, drm_pci_id_list_t *idlist) mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF); + mtx_init(&dev->tsk_lock, "drmtsk", NULL, MTX_DEF); #endif id_entry = drm_find_description(pci_get_vendor(dev->device), diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index c3ecd28b..a066cfc9 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -578,41 +578,42 @@ static void drm_locked_task(void *context, int pending __unused) { struct drm_device *dev = context; - DRM_LOCK(); - for (;;) { - int ret; - - if (drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) - { - dev->lock.file_priv = NULL; /* kernel owned */ - dev->lock.lock_time = jiffies; - atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); - break; /* Got lock */ - } + DRM_SPINLOCK(&dev->tsk_lock); - /* Contention */ -#if defined(__FreeBSD__) && __FreeBSD_version > 500000 - ret = mtx_sleep((void *)&dev->lock.lock_queue, &dev->dev_lock, - PZERO | PCATCH, "drmlk2", 0); -#else - ret = tsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH, - "drmlk2", 0); -#endif - if (ret != 0) - return; + DRM_LOCK(); /* XXX drm_lock_take() should do it's own locking */ + if (dev->locked_task_call == NULL || + drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT) == 0) { + DRM_UNLOCK(); + DRM_SPINUNLOCK(&dev->tsk_lock); + return; } + + dev->lock.file_priv = NULL; /* kernel owned */ + dev->lock.lock_time = jiffies; + atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); + DRM_UNLOCK(); dev->locked_task_call(dev); drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + + dev->locked_task_call = NULL; + + DRM_SPINUNLOCK(&dev->tsk_lock); } void drm_locked_tasklet(struct drm_device *dev, void (*tasklet)(struct drm_device *dev)) { + DRM_SPINLOCK(&dev->tsk_lock); + if (dev->locked_task_call != NULL) { + DRM_SPINUNLOCK(&dev->tsk_lock); + return; + } + dev->locked_task_call = tasklet; + DRM_SPINUNLOCK(&dev->tsk_lock); taskqueue_enqueue(taskqueue_swi, &dev->locked_task); } diff --git a/bsd-core/drm_lock.c b/bsd-core/drm_lock.c index 9101dec8..80ebb71d 100644 --- a/bsd-core/drm_lock.c +++ b/bsd-core/drm_lock.c @@ -180,6 +180,13 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock->context) return EINVAL; + DRM_SPINLOCK(&dev->tsk_lock); + if (dev->locked_task_call != NULL) { + dev->locked_task_call(dev); + dev->locked_task_call = NULL; + } + DRM_SPINUNLOCK(&dev->tsk_lock); + atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); DRM_LOCK(); -- cgit v1.2.3 From b0e4619a396f2db8c594cd0a26fd2f0ab9358095 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Wed, 16 Jul 2008 23:39:25 -0400 Subject: FreeBSD: Fix radeon build --- bsd-core/drmP.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 65d7fae4..b0a23e9c 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -1088,6 +1088,8 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align, dma_addr_t maxaddr); void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); +#define drm_core_ioremap_wc drm_core_ioremap + /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) -- cgit v1.2.3 From 480c317a6ae634d777931eee54fadd2a50a2f650 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Thu, 17 Jul 2008 14:01:04 -0400 Subject: [FreeBSD] drm_irq.c updates for vblank fixes. --- bsd-core/drmP.h | 1 + bsd-core/drm_irq.c | 58 ++++++++++++++++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 23 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index b0a23e9c..2f2ffb3c 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -787,6 +787,7 @@ struct drm_device { atomic_t context_flag; /* Context swapping flag */ int last_context; /* Last current context */ + int vblank_disable_allowed; 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) */ diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index a066cfc9..4b515ad8 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -81,9 +81,15 @@ static void vblank_disable_fn(void *arg) } callout_deactivate(&dev->vblank_disable_timer); + if (!dev->vblank_disable_allowed) + return; + for (i = 0; i < dev->num_crtcs; i++) { if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { + DRM_DEBUG("disabling vblank on crtc %d\n", i); + dev->last_vblank[i] = + dev->driver.get_vblank_counter(dev, i); dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } @@ -181,6 +187,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) atomic_set(&dev->vblank_refcount[i], 0); } + dev->vblank_disable_allowed = 0; + return 0; err: @@ -334,7 +342,6 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) void drm_update_vblank_count(struct drm_device *dev, int crtc) { - unsigned long irqflags; u32 cur_vblank, diff; if (dev->vblank_suspend[crtc]) @@ -348,7 +355,6 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { if (cur_vblank == dev->last_vblank[crtc] - 1) { diff = 0; @@ -364,7 +370,9 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + + DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", + crtc, diff); atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -382,8 +390,10 @@ int drm_vblank_get(struct drm_device *dev, int crtc) ret = dev->driver.enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); - else + else { dev->vblank_enabled[crtc] = 1; + drm_update_vblank_count(dev, crtc); + } } DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); @@ -407,6 +417,8 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; + unsigned long irqflags; + u32 new, diff; int crtc, ret = 0; crtc = modeset->crtc; @@ -417,27 +429,28 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, switch (modeset->cmd) { case _DRM_PRE_MODESET: - dev->vblank_premodeset[crtc] = - dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + if (!dev->vblank_enabled[crtc]) { + dev->vblank_premodeset[crtc] = + dev->driver.get_vblank_counter(dev, crtc); + dev->vblank_suspend[crtc] = 1; + } + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - if (dev->vblank_suspend[crtc]) { - u32 new = dev->driver.get_vblank_counter(dev, crtc); - - /* Compensate for spurious wraparound */ - if (new < dev->vblank_premodeset[crtc]) { - atomic_sub(dev->max_vblank_count + new - - dev->vblank_premodeset[crtc], - &dev->_vblank_count[crtc]); - DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" - " => _vblank_count[%d]-=0x%x\n", crtc, - dev->vblank_premodeset[crtc], new, - crtc, dev->max_vblank_count + new - - dev->vblank_premodeset[crtc]); - } + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + new = dev->driver.get_vblank_counter(dev, crtc); + if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { + if (new > dev->vblank_premodeset[crtc]) + diff = dev->vblank_premodeset[crtc] - new; + else + diff = new; + atomic_add(diff, &dev->_vblank_count[crtc]); } dev->vblank_suspend[crtc] = 0; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; default: ret = EINVAL; @@ -471,7 +484,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (crtc >= dev->num_crtcs) return EINVAL; - drm_update_vblank_count(dev, crtc); seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -569,7 +581,7 @@ void drm_vbl_send_signals(struct drm_device *dev, int crtc ) void drm_handle_vblank(struct drm_device *dev, int crtc) { - drm_update_vblank_count(dev, crtc); + atomic_inc(&dev->_vblank_count[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]); drm_vbl_send_signals(dev, crtc); } -- cgit v1.2.3 From f57f01f02843747d423f2e1c2936f0b987c5b067 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 21 Jul 2008 18:04:02 -0400 Subject: [FreeBSD] Improve upper_32_bits define. Thanks to airlied. --- bsd-core/drmP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 2f2ffb3c..6b91a76b 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -632,7 +632,7 @@ struct drm_ati_pcigart_info { #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1) #endif -#define upper_32_bits(_val) (((u64)(_val)) >> 32) +#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) struct drm_driver_info { int (*load)(struct drm_device *, unsigned long flags); -- cgit v1.2.3 From 2580a065d81be645a14af1e91b8441f7e72fcbe4 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Thu, 24 Jul 2008 00:21:00 -0400 Subject: [FreeBSD] Catch up to linux on vblank-rework --- bsd-core/drmP.h | 4 +-- bsd-core/drm_irq.c | 102 +++++++++++++++++++++-------------------------------- 2 files changed, 42 insertions(+), 64 deletions(-) (limited to 'bsd-core') diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 6b91a76b..326b2202 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -798,8 +798,7 @@ struct drm_device { /* for wraparound handling */ int *vblank_enabled; /* so we don't call enable more than */ /* once per disable */ - u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ - int *vblank_suspend; /* Don't wait while crtc is likely disabled */ + int *vblank_inmodeset; /* Display driver is setting mode */ struct callout vblank_disable_timer; u32 max_vblank_count; /* size of vblank counter register */ int num_crtcs; @@ -932,7 +931,6 @@ void drm_handle_vblank(struct drm_device *dev, int crtc); u32 drm_vblank_count(struct drm_device *dev, int crtc); int drm_vblank_get(struct drm_device *dev, int crtc); void drm_vblank_put(struct drm_device *dev, int crtc); -void drm_update_vblank_count(struct drm_device *dev, int crtc); int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); int drm_vblank_init(struct drm_device *dev, int num_crtcs); void drm_vbl_send_signals(struct drm_device *dev, int crtc); diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 4b515ad8..6e21d41c 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -124,9 +124,7 @@ static void drm_vblank_cleanup(struct drm_device *dev) dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_suspend, sizeof(*dev->vblank_suspend) * + drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs = 0; @@ -169,14 +167,9 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->last_vblank) goto err; - dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), + dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), DRM_MEM_DRIVER); - if (!dev->vblank_premodeset) - goto err; - - dev->vblank_suspend = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); - if (!dev->vblank_suspend) + if (!dev->vblank_inmodeset) goto err; /* Zero per-crtc vblank stuff */ @@ -340,13 +333,10 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) return atomic_read(&dev->_vblank_count[crtc]); } -void drm_update_vblank_count(struct drm_device *dev, int crtc) +static void drm_update_vblank_count(struct drm_device *dev, int crtc) { u32 cur_vblank, diff; - if (dev->vblank_suspend[crtc]) - return; - /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -355,21 +345,13 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); + diff = cur_vblank - dev->last_vblank[crtc]; if (cur_vblank < dev->last_vblank[crtc]) { - if (cur_vblank == dev->last_vblank[crtc] - 1) { - diff = 0; - } else { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; - } + diff += dev->max_vblank_count; DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", crtc, dev->last_vblank[crtc], cur_vblank, diff); - } else { - diff = cur_vblank - dev->last_vblank[crtc]; } - dev->last_vblank[crtc] = cur_vblank; DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", crtc, diff); @@ -408,7 +390,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) /* Last user schedules interrupt disable */ atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 0) - callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, + callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } @@ -418,39 +400,40 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, { struct drm_modeset_ctl *modeset = data; unsigned long irqflags; - u32 new, diff; int crtc, ret = 0; + /* If drm_vblank_init() hasn't been called yet, just no-op */ + if (!dev->num_crtcs) + goto out; + crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { ret = EINVAL; goto out; } + /* + * To avoid all the problems that might happen if interrupts + * were enabled/disabled around or between these calls, we just + * have the kernel take a reference on the CRTC (just once though + * to avoid corrupting the count if multiple, mismatch calls occur), + * so that interrupts remain enabled in the interim. + */ switch (modeset->cmd) { case _DRM_PRE_MODESET: - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - if (!dev->vblank_enabled[crtc]) { - dev->vblank_premodeset[crtc] = - dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; + if (!dev->vblank_inmodeset[crtc]) { + dev->vblank_inmodeset[crtc] = 1; + drm_vblank_get(dev, crtc); } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - new = dev->driver.get_vblank_counter(dev, crtc); - if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { - if (new > dev->vblank_premodeset[crtc]) - diff = dev->vblank_premodeset[crtc] - new; - else - diff = new; - atomic_add(diff, &dev->_vblank_count[crtc]); + if (dev->vblank_inmodeset[crtc]) { + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + dev->vblank_inmodeset[crtc] = 0; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + drm_vblank_put(dev, crtc); } - dev->vblank_suspend[crtc] = 0; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; default: ret = EINVAL; @@ -484,6 +467,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (crtc >= dev->num_crtcs) return EINVAL; + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -493,7 +479,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr case _DRM_VBLANK_ABSOLUTE: break; default: - return EINVAL; + ret = EINVAL; + goto done; } if ((flags & _DRM_VBLANK_NEXTONMISS) && @@ -508,9 +495,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (vbl_sig == NULL) return ENOMEM; - if (dev->vblank_suspend[crtc]) - return EBUSY; - vbl_sig->sequence = vblwait->request.sequence; vbl_sig->signo = vblwait->request.signal; vbl_sig->pid = DRM_CURRENTPID; @@ -524,19 +508,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr #endif ret = EINVAL; } else { - if (!dev->vblank_suspend[crtc]) { - DRM_LOCK(); - /* shared code returns -errno */ - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - ((drm_vblank_count(dev, crtc) - - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); - DRM_UNLOCK(); - } + DRM_LOCK(); + /* shared code returns -errno */ + + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + ((drm_vblank_count(dev, crtc) + - vblwait->request.sequence) <= (1 << 23))); + DRM_UNLOCK(); if (ret != EINTR) { struct timeval now; @@ -548,6 +526,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr } } +done: + drm_vblank_put(dev, crtc); return ret; } -- cgit v1.2.3 From 7a3d6624c47d87bdd46f5394b8cc5130c7a4ed0d Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Fri, 25 Jul 2008 13:46:28 -0400 Subject: [FreeBSD] Duh, we need to actually define the drm_modeset_ctl... --- bsd-core/drm_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'bsd-core') diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 9bd6079f..771e5554 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -125,6 +125,7 @@ static drm_ioctl_desc_t drm_ioctls[256] = { DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), + DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; -- cgit v1.2.3