aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/r128
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2008-09-30 15:14:26 -0400
committerDave Airlie <airlied@linux.ie>2008-10-17 17:10:11 -0400
commit0a3e67a4caac273a3bfc4ced3da364830b1ab241 (patch)
tree02a2e5e76d9dffcb556d09b0eee4d34ebe5d81cb /drivers/gpu/drm/r128
parent2df68b439fcb97a4c55f81516206ef4ee325e28d (diff)
drm: Rework vblank-wait handling to allow interrupt reduction.
Previously, drivers supporting vblank interrupt waits would run the interrupt all the time, or all the time that any 3d client was running, preventing the CPU from sleeping for long when the system was otherwise idle. Now, interrupts are disabled any time that no client is waiting on a vblank event. The new method uses vblank counters on the chipsets when the interrupts are turned off, rather than counting interrupts, so that we can continue to present accurate vblank numbers. Co-author: Michel Dänzer <michel@tungstengraphics.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/r128')
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c29
-rw-r--r--drivers/gpu/drm/r128/r128_drv.h11
-rw-r--r--drivers/gpu/drm/r128/r128_irq.c55
3 files changed, 57 insertions, 38 deletions
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index 6108e7587e12..3265d53ba91f 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
43static struct drm_driver driver = { 43static struct drm_driver driver = {
44 .driver_features = 44 .driver_features =
45 DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | 45 DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
46 DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | 46 DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
47 DRIVER_IRQ_VBL,
48 .dev_priv_size = sizeof(drm_r128_buf_priv_t), 47 .dev_priv_size = sizeof(drm_r128_buf_priv_t),
49 .preclose = r128_driver_preclose, 48 .preclose = r128_driver_preclose,
50 .lastclose = r128_driver_lastclose, 49 .lastclose = r128_driver_lastclose,
51 .vblank_wait = r128_driver_vblank_wait, 50 .get_vblank_counter = r128_get_vblank_counter,
51 .enable_vblank = r128_enable_vblank,
52 .disable_vblank = r128_disable_vblank,
52 .irq_preinstall = r128_driver_irq_preinstall, 53 .irq_preinstall = r128_driver_irq_preinstall,
53 .irq_postinstall = r128_driver_irq_postinstall, 54 .irq_postinstall = r128_driver_irq_postinstall,
54 .irq_uninstall = r128_driver_irq_uninstall, 55 .irq_uninstall = r128_driver_irq_uninstall,
@@ -59,21 +60,20 @@ static struct drm_driver driver = {
59 .ioctls = r128_ioctls, 60 .ioctls = r128_ioctls,
60 .dma_ioctl = r128_cce_buffers, 61 .dma_ioctl = r128_cce_buffers,
61 .fops = { 62 .fops = {
62 .owner = THIS_MODULE, 63 .owner = THIS_MODULE,
63 .open = drm_open, 64 .open = drm_open,
64 .release = drm_release, 65 .release = drm_release,
65 .ioctl = drm_ioctl, 66 .ioctl = drm_ioctl,
66 .mmap = drm_mmap, 67 .mmap = drm_mmap,
67 .poll = drm_poll, 68 .poll = drm_poll,
68 .fasync = drm_fasync, 69 .fasync = drm_fasync,
69#ifdef CONFIG_COMPAT 70#ifdef CONFIG_COMPAT
70 .compat_ioctl = r128_compat_ioctl, 71 .compat_ioctl = r128_compat_ioctl,
71#endif 72#endif
72 }, 73 },
73
74 .pci_driver = { 74 .pci_driver = {
75 .name = DRIVER_NAME, 75 .name = DRIVER_NAME,
76 .id_table = pciidlist, 76 .id_table = pciidlist,
77 }, 77 },
78 78
79 .name = DRIVER_NAME, 79 .name = DRIVER_NAME,
@@ -87,6 +87,7 @@ static struct drm_driver driver = {
87static int __init r128_init(void) 87static int __init r128_init(void)
88{ 88{
89 driver.num_ioctls = r128_max_ioctl; 89 driver.num_ioctls = r128_max_ioctl;
90
90 return drm_init(&driver); 91 return drm_init(&driver);
91} 92}
92 93
diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h
index 011105e51ac6..5898b274279d 100644
--- a/drivers/gpu/drm/r128/r128_drv.h
+++ b/drivers/gpu/drm/r128/r128_drv.h
@@ -29,7 +29,7 @@
29 * Rickard E. (Rik) Faith <faith@valinux.com> 29 * Rickard E. (Rik) Faith <faith@valinux.com>
30 * Kevin E. Martin <martin@valinux.com> 30 * Kevin E. Martin <martin@valinux.com>
31 * Gareth Hughes <gareth@valinux.com> 31 * Gareth Hughes <gareth@valinux.com>
32 * Michel Dänzer <daenzerm@student.ethz.ch> 32 * Michel Dzer <daenzerm@student.ethz.ch>
33 */ 33 */
34 34
35#ifndef __R128_DRV_H__ 35#ifndef __R128_DRV_H__
@@ -97,6 +97,8 @@ typedef struct drm_r128_private {
97 u32 crtc_offset; 97 u32 crtc_offset;
98 u32 crtc_offset_cntl; 98 u32 crtc_offset_cntl;
99 99
100 atomic_t vbl_received;
101
100 u32 color_fmt; 102 u32 color_fmt;
101 unsigned int front_offset; 103 unsigned int front_offset;
102 unsigned int front_pitch; 104 unsigned int front_pitch;
@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
149extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); 151extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
150extern int r128_do_cleanup_cce(struct drm_device * dev); 152extern int r128_do_cleanup_cce(struct drm_device * dev);
151 153
152extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); 154extern int r128_enable_vblank(struct drm_device *dev, int crtc);
153 155extern void r128_disable_vblank(struct drm_device *dev, int crtc);
156extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
154extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); 157extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
155extern void r128_driver_irq_preinstall(struct drm_device * dev); 158extern void r128_driver_irq_preinstall(struct drm_device * dev);
156extern void r128_driver_irq_postinstall(struct drm_device * dev); 159extern int r128_driver_irq_postinstall(struct drm_device *dev);
157extern void r128_driver_irq_uninstall(struct drm_device * dev); 160extern void r128_driver_irq_uninstall(struct drm_device * dev);
158extern void r128_driver_lastclose(struct drm_device * dev); 161extern void r128_driver_lastclose(struct drm_device * dev);
159extern void r128_driver_preclose(struct drm_device * dev, 162extern void r128_driver_preclose(struct drm_device * dev,
diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c
index c76fdca7662d..d7349012a680 100644
--- a/drivers/gpu/drm/r128/r128_irq.c
+++ b/drivers/gpu/drm/r128/r128_irq.c
@@ -35,6 +35,16 @@
35#include "r128_drm.h" 35#include "r128_drm.h"
36#include "r128_drv.h" 36#include "r128_drv.h"
37 37
38u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
39{
40 const drm_r128_private_t *dev_priv = dev->dev_private;
41
42 if (crtc != 0)
43 return 0;
44
45 return atomic_read(&dev_priv->vbl_received);
46}
47
38irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) 48irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
39{ 49{
40 struct drm_device *dev = (struct drm_device *) arg; 50 struct drm_device *dev = (struct drm_device *) arg;
@@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
46 /* VBLANK interrupt */ 56 /* VBLANK interrupt */
47 if (status & R128_CRTC_VBLANK_INT) { 57 if (status & R128_CRTC_VBLANK_INT) {
48 R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); 58 R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
49 atomic_inc(&dev->vbl_received); 59 atomic_inc(&dev_priv->vbl_received);
50 DRM_WAKEUP(&dev->vbl_queue); 60 drm_handle_vblank(dev, 0);
51 drm_vbl_send_signals(dev);
52 return IRQ_HANDLED; 61 return IRQ_HANDLED;
53 } 62 }
54 return IRQ_NONE; 63 return IRQ_NONE;
55} 64}
56 65
57int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) 66int r128_enable_vblank(struct drm_device *dev, int crtc)
58{ 67{
59 unsigned int cur_vblank; 68 drm_r128_private_t *dev_priv = dev->dev_private;
60 int ret = 0;
61 69
62 /* Assume that the user has missed the current sequence number 70 if (crtc != 0) {
63 * by about a day rather than she wants to wait for years 71 DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
64 * using vertical blanks... 72 return -EINVAL;
65 */ 73 }
66 DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
67 (((cur_vblank = atomic_read(&dev->vbl_received))
68 - *sequence) <= (1 << 23)));
69 74
70 *sequence = cur_vblank; 75 R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
76 return 0;
77}
78
79void r128_disable_vblank(struct drm_device *dev, int crtc)
80{
81 if (crtc != 0)
82 DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
71 83
72 return ret; 84 /*
85 * FIXME: implement proper interrupt disable by using the vblank
86 * counter register (if available)
87 *
88 * R128_WRITE(R128_GEN_INT_CNTL,
89 * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
90 */
73} 91}
74 92
75void r128_driver_irq_preinstall(struct drm_device * dev) 93void r128_driver_irq_preinstall(struct drm_device * dev)
@@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
82 R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); 100 R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
83} 101}
84 102
85void r128_driver_irq_postinstall(struct drm_device * dev) 103int r128_driver_irq_postinstall(struct drm_device *dev)
86{ 104{
87 drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; 105 return drm_vblank_init(dev, 1);
88
89 /* Turn on VBL interrupt */
90 R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
91} 106}
92 107
93void r128_driver_irq_uninstall(struct drm_device * dev) 108void r128_driver_irq_uninstall(struct drm_device * dev)