1 /* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
2 *
3 * Copyright 2002 Tungsten Graphics, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors: Keith Whitwell <keith@tungstengraphics.com>
26 *
27 */
28
29
30 #include "i830.h"
31 #include "drmP.h"
32 #include "drm.h"
33 #include "i830_drm.h"
34 #include "i830_drv.h"
35 #include <linux/interrupt.h> /* For task queue support */
36 #include <linux/delay.h>
37
38
DRM(dma_service)39 void DRM(dma_service)(int irq, void *device, struct pt_regs *regs)
40 {
41 drm_device_t *dev = (drm_device_t *)device;
42 drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
43 u16 temp;
44
45 temp = I830_READ16(I830REG_INT_IDENTITY_R);
46 printk("%s: %x\n", __FUNCTION__, temp);
47
48 if(temp == 0)
49 return;
50
51 I830_WRITE16(I830REG_INT_IDENTITY_R, temp);
52
53 if (temp & 2) {
54 atomic_inc(&dev_priv->irq_received);
55 wake_up_interruptible(&dev_priv->irq_queue);
56 }
57 }
58
59
i830_emit_irq(drm_device_t * dev)60 int i830_emit_irq(drm_device_t *dev)
61 {
62 drm_i830_private_t *dev_priv = dev->dev_private;
63 RING_LOCALS;
64
65 DRM_DEBUG("%s\n", __FUNCTION__);
66
67 atomic_inc(&dev_priv->irq_emitted);
68
69 BEGIN_LP_RING(2);
70 OUT_RING( 0 );
71 OUT_RING( GFX_OP_USER_INTERRUPT );
72 ADVANCE_LP_RING();
73
74 return atomic_read(&dev_priv->irq_emitted);
75 }
76
77
i830_wait_irq(drm_device_t * dev,int irq_nr)78 int i830_wait_irq(drm_device_t *dev, int irq_nr)
79 {
80 drm_i830_private_t *dev_priv =
81 (drm_i830_private_t *)dev->dev_private;
82 DECLARE_WAITQUEUE(entry, current);
83 unsigned long end = jiffies + HZ*3;
84 int ret = 0;
85
86 DRM_DEBUG("%s\n", __FUNCTION__);
87
88 if (atomic_read(&dev_priv->irq_received) >= irq_nr)
89 return 0;
90
91 dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
92
93 add_wait_queue(&dev_priv->irq_queue, &entry);
94
95 for (;;) {
96 current->state = TASK_INTERRUPTIBLE;
97 if (atomic_read(&dev_priv->irq_received) >= irq_nr)
98 break;
99 if (time_after(jiffies, end)) {
100 DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n",
101 I830_READ16( I830REG_INT_IDENTITY_R ),
102 I830_READ16( I830REG_INT_MASK_R ),
103 I830_READ16( I830REG_INT_ENABLE_R ),
104 I830_READ16( I830REG_HWSTAM ));
105
106 ret = -EBUSY; /* Lockup? Missed irq? */
107 break;
108 }
109 schedule_timeout(HZ*3);
110 if (signal_pending(current)) {
111 ret = -EINTR;
112 break;
113 }
114 }
115
116 current->state = TASK_RUNNING;
117 remove_wait_queue(&dev_priv->irq_queue, &entry);
118 return ret;
119 }
120
121
122 /* Needs the lock as it touches the ring.
123 */
i830_irq_emit(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)124 int i830_irq_emit( struct inode *inode, struct file *filp, unsigned int cmd,
125 unsigned long arg )
126 {
127 drm_file_t *priv = filp->private_data;
128 drm_device_t *dev = priv->dev;
129 drm_i830_private_t *dev_priv = dev->dev_private;
130 drm_i830_irq_emit_t emit;
131 int result;
132
133 if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
134 DRM_ERROR("i830_irq_emit called without lock held\n");
135 return -EINVAL;
136 }
137
138 if ( !dev_priv ) {
139 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
140 return -EINVAL;
141 }
142
143 if (copy_from_user( &emit, (drm_i830_irq_emit_t *)arg, sizeof(emit) ))
144 return -EFAULT;
145
146 result = i830_emit_irq( dev );
147
148 if ( copy_to_user( emit.irq_seq, &result, sizeof(int) ) ) {
149 DRM_ERROR( "copy_to_user\n" );
150 return -EFAULT;
151 }
152
153 return 0;
154 }
155
156
157 /* Doesn't need the hardware lock.
158 */
i830_irq_wait(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)159 int i830_irq_wait( struct inode *inode, struct file *filp, unsigned int cmd,
160 unsigned long arg )
161 {
162 drm_file_t *priv = filp->private_data;
163 drm_device_t *dev = priv->dev;
164 drm_i830_private_t *dev_priv = dev->dev_private;
165 drm_i830_irq_wait_t irqwait;
166
167 if ( !dev_priv ) {
168 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
169 return -EINVAL;
170 }
171
172 if (copy_from_user( &irqwait, (drm_i830_irq_wait_t *)arg,
173 sizeof(irqwait) ))
174 return -EFAULT;
175
176 return i830_wait_irq( dev, irqwait.irq_seq );
177 }
178
179