aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/via
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
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')
-rw-r--r--drivers/gpu/drm/via/via_drv.c26
-rw-r--r--drivers/gpu/drm/via/via_drv.h16
-rw-r--r--drivers/gpu/drm/via/via_irq.c102
3 files changed, 83 insertions, 61 deletions
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c
index 80c01cdfa37d..0993b441fc42 100644
--- a/drivers/gpu/drm/via/via_drv.c
+++ b/drivers/gpu/drm/via/via_drv.c
@@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = {
40static struct drm_driver driver = { 40static struct drm_driver driver = {
41 .driver_features = 41 .driver_features =
42 DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | 42 DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
43 DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, 43 DRIVER_IRQ_SHARED,
44 .load = via_driver_load, 44 .load = via_driver_load,
45 .unload = via_driver_unload, 45 .unload = via_driver_unload,
46 .context_dtor = via_final_context, 46 .context_dtor = via_final_context,
47 .vblank_wait = via_driver_vblank_wait, 47 .get_vblank_counter = via_get_vblank_counter,
48 .enable_vblank = via_enable_vblank,
49 .disable_vblank = via_disable_vblank,
48 .irq_preinstall = via_driver_irq_preinstall, 50 .irq_preinstall = via_driver_irq_preinstall,
49 .irq_postinstall = via_driver_irq_postinstall, 51 .irq_postinstall = via_driver_irq_postinstall,
50 .irq_uninstall = via_driver_irq_uninstall, 52 .irq_uninstall = via_driver_irq_uninstall,
@@ -59,17 +61,17 @@ static struct drm_driver driver = {
59 .get_reg_ofs = drm_core_get_reg_ofs, 61 .get_reg_ofs = drm_core_get_reg_ofs,
60 .ioctls = via_ioctls, 62 .ioctls = via_ioctls,
61 .fops = { 63 .fops = {
62 .owner = THIS_MODULE, 64 .owner = THIS_MODULE,
63 .open = drm_open, 65 .open = drm_open,
64 .release = drm_release, 66 .release = drm_release,
65 .ioctl = drm_ioctl, 67 .ioctl = drm_ioctl,
66 .mmap = drm_mmap, 68 .mmap = drm_mmap,
67 .poll = drm_poll, 69 .poll = drm_poll,
68 .fasync = drm_fasync, 70 .fasync = drm_fasync,
69 }, 71 },
70 .pci_driver = { 72 .pci_driver = {
71 .name = DRIVER_NAME, 73 .name = DRIVER_NAME,
72 .id_table = pciidlist, 74 .id_table = pciidlist,
73 }, 75 },
74 76
75 .name = DRIVER_NAME, 77 .name = DRIVER_NAME,
diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h
index 2daae81874cd..cafcb844a223 100644
--- a/drivers/gpu/drm/via/via_drv.h
+++ b/drivers/gpu/drm/via/via_drv.h
@@ -75,6 +75,7 @@ typedef struct drm_via_private {
75 struct timeval last_vblank; 75 struct timeval last_vblank;
76 int last_vblank_valid; 76 int last_vblank_valid;
77 unsigned usec_per_vblank; 77 unsigned usec_per_vblank;
78 atomic_t vbl_received;
78 drm_via_state_t hc_state; 79 drm_via_state_t hc_state;
79 char pci_buf[VIA_PCI_BUF_SIZE]; 80 char pci_buf[VIA_PCI_BUF_SIZE];
80 const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; 81 const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
@@ -130,21 +131,24 @@ extern int via_init_context(struct drm_device * dev, int context);
130extern int via_final_context(struct drm_device * dev, int context); 131extern int via_final_context(struct drm_device * dev, int context);
131 132
132extern int via_do_cleanup_map(struct drm_device * dev); 133extern int via_do_cleanup_map(struct drm_device * dev);
133extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); 134extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
135extern int via_enable_vblank(struct drm_device *dev, int crtc);
136extern void via_disable_vblank(struct drm_device *dev, int crtc);
134 137
135extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); 138extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
136extern void via_driver_irq_preinstall(struct drm_device * dev); 139extern void via_driver_irq_preinstall(struct drm_device * dev);
137extern void via_driver_irq_postinstall(struct drm_device * dev); 140extern int via_driver_irq_postinstall(struct drm_device *dev);
138extern void via_driver_irq_uninstall(struct drm_device * dev); 141extern void via_driver_irq_uninstall(struct drm_device * dev);
139 142
140extern int via_dma_cleanup(struct drm_device * dev); 143extern int via_dma_cleanup(struct drm_device * dev);
141extern void via_init_command_verifier(void); 144extern void via_init_command_verifier(void);
142extern int via_driver_dma_quiescent(struct drm_device * dev); 145extern int via_driver_dma_quiescent(struct drm_device * dev);
143extern void via_init_futex(drm_via_private_t * dev_priv); 146extern void via_init_futex(drm_via_private_t *dev_priv);
144extern void via_cleanup_futex(drm_via_private_t * dev_priv); 147extern void via_cleanup_futex(drm_via_private_t *dev_priv);
145extern void via_release_futex(drm_via_private_t * dev_priv, int context); 148extern void via_release_futex(drm_via_private_t *dev_priv, int context);
146 149
147extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); 150extern void via_reclaim_buffers_locked(struct drm_device *dev,
151 struct drm_file *file_priv);
148extern void via_lastclose(struct drm_device *dev); 152extern void via_lastclose(struct drm_device *dev);
149 153
150extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq); 154extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c
index c6bb978a1106..1b966fbdb49f 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;