aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/via/via_irq.c
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/via/via_irq.c
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/via/via_irq.c')
-rw-r--r--drivers/gpu/drm/via/via_irq.c102
1 files changed, 59 insertions, 43 deletions
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c
index c6bb978a110..1b966fbdb49 100644
--- a/drivers/gpu/drm/via/via_irq.c
+++ b/drivers/gpu/drm/via/via_irq.c
@@ -43,7 +43,7 @@
43#define VIA_REG_INTERRUPT 0x200 43#define VIA_REG_INTERRUPT 0x200
44 44
45/* VIA_REG_INTERRUPT */ 45/* VIA_REG_INTERRUPT */
46#define VIA_IRQ_GLOBAL (1 << 31) 46#define VIA_IRQ_GLOBAL (1 << 31)
47#define VIA_IRQ_VBLANK_ENABLE (1 << 19) 47#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
48#define VIA_IRQ_VBLANK_PENDING (1 << 3) 48#define VIA_IRQ_VBLANK_PENDING (1 << 3)
49#define VIA_IRQ_HQV0_ENABLE (1 << 11) 49#define VIA_IRQ_HQV0_ENABLE (1 << 11)
@@ -68,16 +68,15 @@
68 68
69static maskarray_t via_pro_group_a_irqs[] = { 69static maskarray_t via_pro_group_a_irqs[] = {
70 {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 70 {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
71 0x00000000}, 71 0x00000000 },
72 {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 72 {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
73 0x00000000}, 73 0x00000000 },
74 {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, 74 {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
75 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, 75 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
76 {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, 76 {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
77 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, 77 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
78}; 78};
79static int via_num_pro_group_a = 79static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
80 sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
81static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; 80static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
82 81
83static maskarray_t via_unichrome_irqs[] = { 82static maskarray_t via_unichrome_irqs[] = {
@@ -86,14 +85,24 @@ static maskarray_t via_unichrome_irqs[] = {
86 {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, 85 {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
87 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} 86 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
88}; 87};
89static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t); 88static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
90static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; 89static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
91 90
91
92static unsigned time_diff(struct timeval *now, struct timeval *then) 92static unsigned time_diff(struct timeval *now, struct timeval *then)
93{ 93{
94 return (now->tv_usec >= then->tv_usec) ? 94 return (now->tv_usec >= then->tv_usec) ?
95 now->tv_usec - then->tv_usec : 95 now->tv_usec - then->tv_usec :
96 1000000 - (then->tv_usec - now->tv_usec); 96 1000000 - (then->tv_usec - now->tv_usec);
97}
98
99u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
100{
101 drm_via_private_t *dev_priv = dev->dev_private;
102 if (crtc != 0)
103 return 0;
104
105 return atomic_read(&dev_priv->vbl_received);
97} 106}
98 107
99irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) 108irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
@@ -108,23 +117,22 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
108 117
109 status = VIA_READ(VIA_REG_INTERRUPT); 118 status = VIA_READ(VIA_REG_INTERRUPT);
110 if (status & VIA_IRQ_VBLANK_PENDING) { 119 if (status & VIA_IRQ_VBLANK_PENDING) {
111 atomic_inc(&dev->vbl_received); 120 atomic_inc(&dev_priv->vbl_received);
112 if (!(atomic_read(&dev->vbl_received) & 0x0F)) { 121 if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
113 do_gettimeofday(&cur_vblank); 122 do_gettimeofday(&cur_vblank);
114 if (dev_priv->last_vblank_valid) { 123 if (dev_priv->last_vblank_valid) {
115 dev_priv->usec_per_vblank = 124 dev_priv->usec_per_vblank =
116 time_diff(&cur_vblank, 125 time_diff(&cur_vblank,
117 &dev_priv->last_vblank) >> 4; 126 &dev_priv->last_vblank) >> 4;
118 } 127 }
119 dev_priv->last_vblank = cur_vblank; 128 dev_priv->last_vblank = cur_vblank;
120 dev_priv->last_vblank_valid = 1; 129 dev_priv->last_vblank_valid = 1;
121 } 130 }
122 if (!(atomic_read(&dev->vbl_received) & 0xFF)) { 131 if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
123 DRM_DEBUG("US per vblank is: %u\n", 132 DRM_DEBUG("US per vblank is: %u\n",
124 dev_priv->usec_per_vblank); 133 dev_priv->usec_per_vblank);
125 } 134 }
126 DRM_WAKEUP(&dev->vbl_queue); 135 drm_handle_vblank(dev, 0);
127 drm_vbl_send_signals(dev);
128 handled = 1; 136 handled = 1;
129 } 137 }
130 138
@@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
145 /* Acknowlege interrupts */ 153 /* Acknowlege interrupts */
146 VIA_WRITE(VIA_REG_INTERRUPT, status); 154 VIA_WRITE(VIA_REG_INTERRUPT, status);
147 155
156
148 if (handled) 157 if (handled)
149 return IRQ_HANDLED; 158 return IRQ_HANDLED;
150 else 159 else
@@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
163 } 172 }
164} 173}
165 174
166int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) 175int via_enable_vblank(struct drm_device *dev, int crtc)
167{ 176{
168 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 177 drm_via_private_t *dev_priv = dev->dev_private;
169 unsigned int cur_vblank; 178 u32 status;
170 int ret = 0;
171 179
172 DRM_DEBUG("\n"); 180 if (crtc != 0) {
173 if (!dev_priv) { 181 DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
174 DRM_ERROR("called with no initialization\n");
175 return -EINVAL; 182 return -EINVAL;
176 } 183 }
177 184
178 viadrv_acknowledge_irqs(dev_priv); 185 status = VIA_READ(VIA_REG_INTERRUPT);
186 VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
187
188 VIA_WRITE8(0x83d4, 0x11);
189 VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
179 190
180 /* Assume that the user has missed the current sequence number 191 return 0;
181 * by about a day rather than she wants to wait for years 192}
182 * using vertical blanks...
183 */
184 193
185 DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, 194void via_disable_vblank(struct drm_device *dev, int crtc)
186 (((cur_vblank = atomic_read(&dev->vbl_received)) - 195{
187 *sequence) <= (1 << 23))); 196 drm_via_private_t *dev_priv = dev->dev_private;
188 197
189 *sequence = cur_vblank; 198 VIA_WRITE8(0x83d4, 0x11);
190 return ret; 199 VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
200
201 if (crtc != 0)
202 DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
191} 203}
192 204
193static int 205static int
@@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
239 return ret; 251 return ret;
240} 252}
241 253
254
242/* 255/*
243 * drm_dma.h hooks 256 * drm_dma.h hooks
244 */ 257 */
@@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev)
292 } 305 }
293} 306}
294 307
295void via_driver_irq_postinstall(struct drm_device * dev) 308int via_driver_irq_postinstall(struct drm_device *dev)
296{ 309{
297 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 310 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
298 u32 status; 311 u32 status;
299 312
300 DRM_DEBUG("\n"); 313 DRM_DEBUG("via_driver_irq_postinstall\n");
301 if (dev_priv) { 314 if (!dev_priv)
302 status = VIA_READ(VIA_REG_INTERRUPT); 315 return -EINVAL;
303 VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
304 | dev_priv->irq_enable_mask);
305 316
306 /* Some magic, oh for some data sheets ! */ 317 drm_vblank_init(dev, 1);
318 status = VIA_READ(VIA_REG_INTERRUPT);
319 VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
320 | dev_priv->irq_enable_mask);
307 321
308 VIA_WRITE8(0x83d4, 0x11); 322 /* Some magic, oh for some data sheets ! */
309 VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); 323 VIA_WRITE8(0x83d4, 0x11);
324 VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
310 325
311 } 326 return 0;
312} 327}
313 328
314void via_driver_irq_uninstall(struct drm_device * dev) 329void via_driver_irq_uninstall(struct drm_device * dev)
@@ -352,7 +367,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
352 367
353 switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { 368 switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
354 case VIA_IRQ_RELATIVE: 369 case VIA_IRQ_RELATIVE:
355 irqwait->request.sequence += atomic_read(&cur_irq->irq_received); 370 irqwait->request.sequence +=
371 atomic_read(&cur_irq->irq_received);
356 irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; 372 irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
357 case VIA_IRQ_ABSOLUTE: 373 case VIA_IRQ_ABSOLUTE:
358 break; 374 break;