aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mga
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/mga
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/mga')
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c29
-rw-r--r--drivers/gpu/drm/mga/mga_drv.h6
-rw-r--r--drivers/gpu/drm/mga/mga_irq.c74
3 files changed, 73 insertions, 36 deletions
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
index 5572939fc7d1..97ee566ef749 100644
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ b/drivers/gpu/drm/mga/mga_drv.c
@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = {
45static struct drm_driver driver = { 45static struct drm_driver driver = {
46 .driver_features = 46 .driver_features =
47 DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | 47 DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
48 DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | 48 DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
49 DRIVER_IRQ_VBL,
50 .dev_priv_size = sizeof(drm_mga_buf_priv_t), 49 .dev_priv_size = sizeof(drm_mga_buf_priv_t),
51 .load = mga_driver_load, 50 .load = mga_driver_load,
52 .unload = mga_driver_unload, 51 .unload = mga_driver_unload,
53 .lastclose = mga_driver_lastclose, 52 .lastclose = mga_driver_lastclose,
54 .dma_quiescent = mga_driver_dma_quiescent, 53 .dma_quiescent = mga_driver_dma_quiescent,
55 .device_is_agp = mga_driver_device_is_agp, 54 .device_is_agp = mga_driver_device_is_agp,
56 .vblank_wait = mga_driver_vblank_wait, 55 .get_vblank_counter = mga_get_vblank_counter,
56 .enable_vblank = mga_enable_vblank,
57 .disable_vblank = mga_disable_vblank,
57 .irq_preinstall = mga_driver_irq_preinstall, 58 .irq_preinstall = mga_driver_irq_preinstall,
58 .irq_postinstall = mga_driver_irq_postinstall, 59 .irq_postinstall = mga_driver_irq_postinstall,
59 .irq_uninstall = mga_driver_irq_uninstall, 60 .irq_uninstall = mga_driver_irq_uninstall,
@@ -64,20 +65,20 @@ static struct drm_driver driver = {
64 .ioctls = mga_ioctls, 65 .ioctls = mga_ioctls,
65 .dma_ioctl = mga_dma_buffers, 66 .dma_ioctl = mga_dma_buffers,
66 .fops = { 67 .fops = {
67 .owner = THIS_MODULE, 68 .owner = THIS_MODULE,
68 .open = drm_open, 69 .open = drm_open,
69 .release = drm_release, 70 .release = drm_release,
70 .ioctl = drm_ioctl, 71 .ioctl = drm_ioctl,
71 .mmap = drm_mmap, 72 .mmap = drm_mmap,
72 .poll = drm_poll, 73 .poll = drm_poll,
73 .fasync = drm_fasync, 74 .fasync = drm_fasync,
74#ifdef CONFIG_COMPAT 75#ifdef CONFIG_COMPAT
75 .compat_ioctl = mga_compat_ioctl, 76 .compat_ioctl = mga_compat_ioctl,
76#endif 77#endif
77 }, 78 },
78 .pci_driver = { 79 .pci_driver = {
79 .name = DRIVER_NAME, 80 .name = DRIVER_NAME,
80 .id_table = pciidlist, 81 .id_table = pciidlist,
81 }, 82 },
82 83
83 .name = DRIVER_NAME, 84 .name = DRIVER_NAME,
diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h
index f6ebd24bd587..88257c276eb9 100644
--- a/drivers/gpu/drm/mga/mga_drv.h
+++ b/drivers/gpu/drm/mga/mga_drv.h
@@ -120,6 +120,7 @@ typedef struct drm_mga_private {
120 u32 clear_cmd; 120 u32 clear_cmd;
121 u32 maccess; 121 u32 maccess;
122 122
123 atomic_t vbl_received; /**< Number of vblanks received. */
123 wait_queue_head_t fence_queue; 124 wait_queue_head_t fence_queue;
124 atomic_t last_fence_retired; 125 atomic_t last_fence_retired;
125 u32 next_fence_to_post; 126 u32 next_fence_to_post;
@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
181extern int mga_warp_init(drm_mga_private_t * dev_priv); 182extern int mga_warp_init(drm_mga_private_t * dev_priv);
182 183
183 /* mga_irq.c */ 184 /* mga_irq.c */
185extern int mga_enable_vblank(struct drm_device *dev, int crtc);
186extern void mga_disable_vblank(struct drm_device *dev, int crtc);
187extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
184extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); 188extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
185extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); 189extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
186extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); 190extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
187extern void mga_driver_irq_preinstall(struct drm_device * dev); 191extern void mga_driver_irq_preinstall(struct drm_device * dev);
188extern void mga_driver_irq_postinstall(struct drm_device * dev); 192extern int mga_driver_irq_postinstall(struct drm_device *dev);
189extern void mga_driver_irq_uninstall(struct drm_device * dev); 193extern void mga_driver_irq_uninstall(struct drm_device * dev);
190extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, 194extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
191 unsigned long arg); 195 unsigned long arg);
diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c
index 9302cb8f0f83..bab42f41188b 100644
--- a/drivers/gpu/drm/mga/mga_irq.c
+++ b/drivers/gpu/drm/mga/mga_irq.c
@@ -1,5 +1,6 @@
1/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- 1/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
2 * 2 */
3/*
3 * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. 4 * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
4 * 5 *
5 * The Weather Channel (TM) funded Tungsten Graphics to develop the 6 * The Weather Channel (TM) funded Tungsten Graphics to develop the
@@ -35,6 +36,18 @@
35#include "mga_drm.h" 36#include "mga_drm.h"
36#include "mga_drv.h" 37#include "mga_drv.h"
37 38
39u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
40{
41 const drm_mga_private_t *const dev_priv =
42 (drm_mga_private_t *) dev->dev_private;
43
44 if (crtc != 0)
45 return 0;
46
47 return atomic_read(&dev_priv->vbl_received);
48}
49
50
38irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) 51irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
39{ 52{
40 struct drm_device *dev = (struct drm_device *) arg; 53 struct drm_device *dev = (struct drm_device *) arg;
@@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
47 /* VBLANK interrupt */ 60 /* VBLANK interrupt */
48 if (status & MGA_VLINEPEN) { 61 if (status & MGA_VLINEPEN) {
49 MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); 62 MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
50 atomic_inc(&dev->vbl_received); 63 atomic_inc(&dev_priv->vbl_received);
51 DRM_WAKEUP(&dev->vbl_queue); 64 drm_handle_vblank(dev, 0);
52 drm_vbl_send_signals(dev);
53 handled = 1; 65 handled = 1;
54 } 66 }
55 67
@@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
58 const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); 70 const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
59 const u32 prim_end = MGA_READ(MGA_PRIMEND); 71 const u32 prim_end = MGA_READ(MGA_PRIMEND);
60 72
73
61 MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); 74 MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
62 75
63 /* In addition to clearing the interrupt-pending bit, we 76 /* In addition to clearing the interrupt-pending bit, we
@@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
72 handled = 1; 85 handled = 1;
73 } 86 }
74 87
75 if (handled) { 88 if (handled)
76 return IRQ_HANDLED; 89 return IRQ_HANDLED;
77 }
78 return IRQ_NONE; 90 return IRQ_NONE;
79} 91}
80 92
81int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) 93int mga_enable_vblank(struct drm_device *dev, int crtc)
82{ 94{
83 unsigned int cur_vblank; 95 drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
84 int ret = 0;
85 96
86 /* Assume that the user has missed the current sequence number 97 if (crtc != 0) {
87 * by about a day rather than she wants to wait for years 98 DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
88 * using vertical blanks... 99 crtc);
89 */ 100 return 0;
90 DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, 101 }
91 (((cur_vblank = atomic_read(&dev->vbl_received))
92 - *sequence) <= (1 << 23)));
93 102
94 *sequence = cur_vblank; 103 MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
104 return 0;
105}
95 106
96 return ret; 107
108void mga_disable_vblank(struct drm_device *dev, int crtc)
109{
110 if (crtc != 0) {
111 DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
112 crtc);
113 }
114
115 /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
116 * a nice hardware counter that tracks the number of refreshes when
117 * the interrupt is disabled, and the kernel doesn't know the refresh
118 * rate to calculate an estimate.
119 */
120 /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
97} 121}
98 122
99int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) 123int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
@@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
125 MGA_WRITE(MGA_ICLEAR, ~0); 149 MGA_WRITE(MGA_ICLEAR, ~0);
126} 150}
127 151
128void mga_driver_irq_postinstall(struct drm_device * dev) 152int mga_driver_irq_postinstall(struct drm_device *dev)
129{ 153{
130 drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 154 drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
155 int ret;
156
157 ret = drm_vblank_init(dev, 1);
158 if (ret)
159 return ret;
131 160
132 DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); 161 DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
133 162
134 /* Turn on vertical blank interrupt and soft trap interrupt. */ 163 /* Turn on soft trap interrupt. Vertical blank interrupts are enabled
135 MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); 164 * in mga_enable_vblank.
165 */
166 MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
167 return 0;
136} 168}
137 169
138void mga_driver_irq_uninstall(struct drm_device * dev) 170void mga_driver_irq_uninstall(struct drm_device * dev)